从 50 行 Python 到 ReAct 循环:把 AI Agent 的模型通道切到 TaoToken
我用 50 行 Python 写过一个最天真的 AI Agent:一个while True循环,每轮把 system prompt、用户消息和 tool 结果发回 LLM,用if not message.tool_calls判断该结束还是继续调工具。它能跑get_current_date、calculate、get_weather,后来还扩到了web_search、read_file、write_file,甚至能通过 MCP 客户端从外部服务器发现工具。真正让我卡住的不是循环逻辑,而是云端大脑那一步——client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])里的 Key 和 Base URL 到底怎么配才稳。这篇就把这条通道换成 TaoToken(官网:https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=),只改 client 初始化,ReAct 循环一行不动。
一、原问题与场景:ReAct 长会话为什么先卡在通道上
先把这个 Agent 的骨架说清楚,不然后面改配置会没底。
它的核心就是run_agent(task, client, model)里那个死循环:
while True: response = client.chat.completions.create( model=model, messages=messages, tools=TOOLS, tool_choice="auto", ) message = response.choices[0].message messages.append(message) if not message.tool_calls: return message.content for tool_call in message.tool_calls: name = tool_call.function.name args = json.loads(tool_call.function.arguments) print(f" > calling {name}({args})") fn = TOOL_FUNCTIONS.get(name) result = fn(**args) if fn else f"Unknown tool: {name}" messages.append({ "role": "tool", "tool_call_id": tool_call.id, "content": result, })关键行是if not message.tool_calls。模型返回纯文本、不请求工具,就说明它觉得信息够了,Agent 退出;一旦请求了工具,就执行、把结果追加进messages,再发回模型进入下一轮。messages列表就是这个 Agent 的短期记忆。
问题出在“长会话 + 多工具”这个组合上。一个任务里模型可能连续触发get_current_date、calculate、get_weather三次调用,每轮都要把不断变长的messages重新发一遍。ReAct 循环越转,Token 消耗越像滚雪球。这时候云端大脑的通道必须满足两个条件:Key 稳定、Base URL 稳定。原文里OpenAI(api_key=os.environ["OPENAI_API_KEY"])这一步,就是我们要动的地方。
TaoToken 在这里的角色很明确:它只提供 Key 和 Base URL,不替 Agent 执行 ReAct 循环,也不会去调用get_current_date、calculate这些工具。循环、工具、判断逻辑全在你自己这 50 行里,它只负责把“云端大脑”这一跳接稳。
二、TaoToken 前置:拿 Key、认 Base URL
动手前先把两样东西准备好。
第一,打开 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 创建账号并生成 Key。这个 Key 就是后面api_key要填的值,本文统一用YOUR_API_KEY占位,你替换成自己生成的那串即可。
第二,记住兼容通道的 Base URL:https://taotoken.net/api。注意这个地址不带任何 UTM 参数,就是干净的 API 入口。
这里要划清边界,避免误解:
- TaoToken 提供的是 OpenAI 兼容的模型调用通道,你的
client.chat.completions.create(...)照常发。 - 它不接管你的
while True,不判断message.tool_calls,不执行任何本地工具函数。 - 你的
get_current_date、calculate、get_weather、web_search、read_file、write_file仍然跑在你自己机器上。
换句话说,换通道换的是“模型在哪”,不是“Agent 怎么跑”。
如果你后面要长期跑编码类 Agent、反复做多工具 ReAct,可以顺带了解下 Coding Plan(https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=),但本篇的重点还是把这条基础通道配通。
三、可复制配置:只改 client 初始化
原文最小实现里这一行:
client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])改成走 TaoToken 兼容通道:
import os from openai import OpenAI client = OpenAI( api_key=os.environ.get("TAOTOKEN_API_KEY", "YOUR_API_KEY"), base_url="https://taotoken.net/api", )就这两处:api_key用 TaoToken 生成的 Key,base_url设成https://taotoken.net/api。run_agent函数、TOOLS定义、TOOL_FUNCTIONS映射,全都不用动。
本地 Ollama 保持原样。原文里本地模型那段是:
ollama_client = OpenAI( base_url="http://localhost:11434/v1", api_key="ollama", )这个base_url仍然是http://localhost:11434/v1,不要改成 TaoToken。本地就是本地,云端就是云端,两条通道各走各的。
混合模式里的云端 client 也走同一通道。原文的ask_cloud_expert是这样:
def ask_cloud_expert(question: str) -> str: cloud_client = OpenAI(api_key=os.environ["OPENAI_API_KEY"]) response = cloud_client.chat.completions.create( model="gpt-4o", messages=[{"role": "user", "content": question}], ) return response.choices[0].message.content把里面的cloud_client也换成 TaoToken 通道:
def ask_cloud_expert(question: str) -> str: cloud_client = OpenAI( api_key=os.environ.get("TAOTOKEN_API_KEY", "YOUR_API_KEY"), base_url="https://taotoken.net/api", ) response = cloud_client.chat.completions.create( model="gpt-4o", messages=[{"role": "user", "content": question}], ) return response.choices[0].message.content这样本地模型负责循环和简单工具,遇到需要深推理的问题才委托给云端,而云端这一跳统一走 TaoToken。
建议把 Key 放进环境变量,别硬编码:
export TAOTOKEN_API_KEY="YOUR_API_KEY"四、验证请求:重跑 run_agent 看 tool_calls
配置改完,直接重跑原来的入口:
if __name__ == "__main__": task = "What's today's date? Also, what is 15% of 847? And what's the weather in Tokyo?" print(f"Task: {task}\n") answer = run_agent(task, client) print(f"\nAnswer: {answer}")判断请求是否真的走了 TaoToken 通道,看两点:
第一,Agent 是否仍按原逻辑触发tool_calls。终端里应该照旧打印出:
> calling get_current_date({}) > calling calculate({'expression': '847 * 0.15'}) > calling get_weather({'city': 'Tokyo'})这几行> calling ...是run_agent里print(f" > calling {name}({args})")打出来的,说明模型确实返回了结构化 tool 调用,循环正常在转。
第二,最终是否组装出答案,类似:
Answer: Today is 2026-04-30 09:14:22. 15% of 847 is 127.05. The weather in Tokyo is 72°F and partly cloudy.只要> calling ...照常出现、最终答案照常返回,就说明请求已经走 TaoToken 通道,而 ReAct 循环、工具执行、if not message.tool_calls判断这些逻辑一个都没变。
想单独确认通道本身通不通,可以先用模型对话(https://taotoken.net/model-chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=)发一条最简单的消息,排除是 Agent 逻辑还是通道的问题。
五、本篇常见错排查
错误 1:Agent 立刻返回、从不调用任何工具。这大概率不是通道问题,而是模型不支持结构化 function calling。原文里 Mistral 7B 就踩过这个坑——它用散文“描述”要调哪个工具,response.tool_calls每次都是空的,于是if not message.tool_calls直接命中,Agent 带着一段文字就退出了。先换一个稳定支持 function calling 的模型试试,别急着怀疑 TaoToken 通道。
错误 2:base_url写错或漏写。漏写base_url会默认打到 OpenAI 官方地址,Key 自然对不上。确认是https://taotoken.net/api,不要多加斜杠后缀,也不要带 UTM 参数。
错误 3:Key 没生效。检查api_key是不是真的读到了YOUR_API_KEY对应的值。用环境变量的话,确认export在当前 shell 生效,或者干脆先临时写死排查一次。
错误 4:把 Ollama 的 base_url 也改了。本地那段必须保持http://localhost:11434/v1。混着改会让本地模型调用直接失败。
错误 5:工具函数抛异常导致 Agent 崩。原文这个 50 行版本没有错误处理,工具一抛异常整个循环就挂。这跟通道无关,但排查时容易误判。可以在fn(**args)外面包一层 try/except 先兜住。
如果上面都排完还是不通,去 API Keys 页面(https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=)核对 Key 状态,再对照接入文档(https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=)确认参数格式。
六、语义一致 CTA
回到最初那个问题:50 行 Python 的 ReAct 循环,模型通道改到 TaoToken 行不行?答案是行,而且改动极小——只动OpenAI(...)的api_key和base_url两处,while True、if not message.tool_calls、六个工具函数、MCP 客户端发现工具的逻辑,全部原样保留。
TaoToken 在这里只做一件事:给你的云端大脑提供稳定的 Key 和 Base URL。它不替你跑循环,不替你调工具,也不改变你理解 Agent 的方式。
- 要拿 Key、配通道、排接入问题:走 API Keys(https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=)和接入文档(https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=)。
- 要单独验证模型通不通:用模型对话(https://taotoken.net/model-chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=)。
- 要长期跑编码类 Agent、反复做多工具 ReAct:看 Coding Plan(https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=)。
先把这 50 行的天真版本跑通,再决定要不要上框架。通道这一跳稳了,剩下的循环逻辑你早就看懂了。