1. 为什么你的 Agent 总是“跑得通但用不住”
很多人第一次接触 Agent 工程,都会经历一个相似的曲线:本地用 LangChain 拼出一个能调用搜索、能读文件、能回答问题的智能体,兴奋地截图发群里;然后把它丢给真实用户,三天后收到一堆“它又乱调工具了”“同一个问题每次答案都不一样”“昨天还好好的今天崩了”的反馈。
问题不在于模型不够强,而在于我们把“能跑”当成了“能用”。传统后端服务的输入是结构化的,参数类型、取值范围、边界条件都能在代码里写死;而 Agent 的输入是一句自然语言,模型要在开放空间里推理该不该调工具、调哪个、传什么参数。这种不确定性是它的能力来源,也是它难以驾驭的根源。
Agent 工程要解决的,就是把这团不确定性收拢成可观测、可迭代、可回滚的工程系统。它至少包含四件事:统一的模型接入层、可复制的配置骨架、可验证的调用链、以及出错时能快速定位的排查路径。这篇就围绕这四件事展开,用 TaoToken 作为统一 Key 入口,把 LangChain 智能体从零搭到能稳定跑起来。
适合谁看:已经会写 Python、听过 LangChain 但没系统搭过 Agent 的开发者;手里有多个模型 Key、被密钥管理搞烦的人;以及想把智能体从 demo 推进到小范围试用的团队。下面所有配置和命令都可以直接复制,改掉 Key 就能跑。
2. 前置准备:用 TaoToken 统一管理模型 Key
在写第一行 Agent 代码之前,先把 Key 这件事理顺。我见过太多项目把 OpenAI、Claude、国产模型的 Key 散落在.env、config.py、甚至硬编码在 notebook 里,换一个模型就要改五处代码。Agent 工程的第一步不是写 prompt,而是把模型接入层抽象出来。
TaoToken 在这里扮演的角色是统一入口:你只需要一个 API Key,就能通过兼容 OpenAI 协议的接口访问不同的大模型,Agent 代码里的base_url和api_key保持稳定,切换模型只改model字段。官网地址是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 端点是 https://taotoken.net/api 。
具体操作分三步。第一步,打开控制台创建 Key,入口在 https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite ,登录后在 API Keys 页面点新建,复制那串sk-开头的字符串。第二步,如果你只是想先验证模型通不通,可以直接用模型对话页面发一条消息,地址是 https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_content=model_chat&utm_campaign=rewrite ,不用写代码就能确认 Key 有效。第三步,把 Key 写进环境变量,别写进代码:
export TAOTOKEN_API_KEY="sk-你的key" export TAOTOKEN_BASE_URL="https://taotoken.net/api"注意:环境变量方式在本地开发够用,但生产环境建议用密钥管理服务或至少放进
.env并加入.gitignore。我踩过的坑是把 Key 提交到公开仓库,十分钟内就被扫到并产生了异常调用。
如果你打算长期跑编码类 Agent 或做多轮工具调用,可以了解一下 Coding Plan,入口在 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite ,它更适合高频、长链路的智能体场景。接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite ,遇到协议细节可以对照查。
3. 可复制的配置骨架:config.toml 与 settings.json
Agent 工程要可复制,配置就不能散。我习惯把模型参数、工具开关、超时重试这些集中到两个文件:config.toml管模型和运行时,settings.json管 Agent 行为和工具注册。这样换环境只改配置,不动业务代码。
先看config.toml:
[llm] provider = "openai-compatible" base_url = "https://taotoken.net/api" api_key_env = "TAOTOKEN_API_KEY" model = "gpt-4o-mini" temperature = 0.2 max_tokens = 2048 timeout = 60 max_retries = 3 [agent] name = "research-assistant" max_iterations = 8 verbose = true handle_parsing_errors = true [memory] type = "buffer_window" window_size = 10 [tools] enable_search = true enable_calculator = true enable_file_reader = false几个参数值得说明。temperature设 0.2 而不是 0,是因为 Agent 需要一点探索性来选工具,但太高又会乱调;max_iterations限制推理轮数,防止死循环烧 token;handle_parsing_errors = true让模型输出格式不对时自动重试而不是直接抛异常,这个在真实环境里能救很多次。
再看settings.json,它描述工具和提示词:
{ "system_prompt": "你是一个严谨的研究助手。回答前先判断是否需要调用工具。需要实时信息时调用 search,需要计算时调用 calculator。每次只调用一个工具,拿到结果后再决定下一步。", "tools": [ { "name": "search", "description": "搜索实时信息,输入为查询字符串", "enabled": true }, { "name": "calculator", "description": "执行数学计算,输入为表达式字符串", "enabled": true } ], "output": { "format": "text", "include_tool_trace": true } }include_tool_trace打开后,每次工具调用都会记录在返回结构里,这是后面排查问题的关键。没有 trace,你只能看到最终答案,根本不知道它中间调了什么、传了什么参数。
4. 用 LangChain 组装智能体并接入统一 Key
配置就绪后,写代码。核心思路是:从配置文件读参数,用ChatOpenAI指向 TaoToken 的兼容端点,把工具注册进去,再用AgentExecutor串起来。
import os import json import tomllib from langchain_openai import ChatOpenAI from langchain.agents import AgentExecutor, create_openai_tools_agent from langchain_core.prompts import ChatPromptTemplate from langchain_core.tools import tool # 读取配置 with open("config.toml", "rb") as f: config = tomllib.load(f) with open("settings.json", "r", encoding="utf-8") as f: settings = json.load(f) # 初始化模型,指向 TaoToken 统一端点 llm = ChatOpenAI( model=config["llm"]["model"], base_url=config["llm"]["base_url"], api_key=os.environ[config["llm"]["api_key_env"]], temperature=config["llm"]["temperature"], max_tokens=config["llm"]["max_tokens"], timeout=config["llm"]["timeout"], max_retries=config["llm"]["max_retries"], ) # 定义工具 @tool def search(query: str) -> str: """搜索实时信息,输入为查询字符串""" return f"[模拟搜索结果] 关于 {query} 的最新信息" @tool def calculator(expression: str) -> str: """执行数学计算,输入为表达式字符串""" return str(eval(expression)) tools = [search, calculator] # 构建提示词 prompt = ChatPromptTemplate.from_messages([ ("system", settings["system_prompt"]), ("human", "{input}"), ("placeholder", "{agent_scratchpad}"), ]) # 组装 Agent agent = create_openai_tools_agent(llm, tools, prompt) executor = AgentExecutor( agent=agent, tools=tools, max_iterations=config["agent"]["max_iterations"], verbose=config["agent"]["verbose"], handle_parsing_errors=config["agent"]["handle_parsing_errors"], return_intermediate_steps=True, )这里有几个工程细节。return_intermediate_steps=True让executor.invoke的返回里带上每一步的工具调用记录,配合前面的include_tool_trace就能完整还原推理链。create_openai_tools_agent用的是 OpenAI 的 function calling 协议,TaoToken 的兼容端点支持这套协议,所以不用改任何调用方式。
跑起来:
result = executor.invoke({"input": "帮我算一下 128 乘以 37 等于多少"}) print(result["output"]) for step in result["intermediate_steps"]: print("工具:", step[0].tool, "参数:", step[0].tool_input)如果一切正常,你会看到它先调用calculator,拿到结果后再组织语言回答。这一步跑通,说明统一 Key 接入和 Agent 调用链都通了。
5. 验证请求:确认调用链真的走通了
代码跑通不等于链路正确。我习惯用三个动作验证:单模型直连、单工具调用、多轮推理。
单模型直连最简单,用 curl 打一发:
curl https://taotoken.net/api/chat/completions \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-4o-mini", "messages": [{"role": "user", "content": "回复 OK"}] }'返回里有choices[0].message.content就说明 Key 和端点没问题。这一步能排除掉大部分“Key 无效”“base_url 写错”的低级问题。
单工具调用看intermediate_steps里是否出现了预期的工具名和参数。如果模型直接回答而没调工具,通常是工具描述不够清晰,或者 system prompt 没强调“需要计算时调用 calculator”。
多轮推理则用一个需要两步的问题,比如“先搜索 LangChain 最新版本,再把版本号乘以 2”。观察它是否先调 search、再调 calculator。如果它把两步合并成一次调用,说明max_iterations或提示词需要调整。
提示:验证阶段把
verbose设为 true,控制台会打印完整的推理过程。上线前再关掉,避免日志泄露敏感信息。
6. 本篇常见错误排查
报错一:AuthenticationError: Incorrect API key先确认环境变量是否真的导出成功,echo $TAOTOKEN_API_KEY看有没有值。如果值对但还报错,检查base_url是否写成了https://taotoken.net/api/带尾斜杠,某些客户端对尾斜杠敏感。Key 本身可以在 API Keys 页面重新生成,入口 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api_keys&utm_campaign=rewrite 。
报错二:model not found模型名要和端点支持的列表一致。不同模型对temperature的取值范围要求不同,有的只接受 0 到 1,设成 2 会报参数错误。切换模型时先只改model字段,其他参数保持默认。
报错三:Agent 陷入循环,反复调用同一个工具这是max_iterations没设或设太大。设成 8 左右,同时检查工具描述是否让模型产生了歧义。如果 search 和 calculator 的描述都写“处理信息”,模型就会分不清。描述要具体到输入输出。
报错四:Could not parse LLM output模型返回了不符合 function calling 格式的内容。把handle_parsing_errors设为 true 让它自动重试,同时在 system prompt 里明确“只输出工具调用或最终答案,不要输出额外解释”。
报错五:超时长链路 Agent 容易超时。把timeout调到 60 秒以上,max_retries设 3。如果还是频繁超时,考虑用 Coding Plan 这类更适合长任务的方案,入口 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite 。
7. 下一步:把 Agent 推进到可迭代状态
跑通第一个智能体只是起点。真正让 Agent 工程产生价值的是迭代闭环:记录每次调用的 trace、定期回看失败案例、找到模式后调整提示词或工具描述、再发布验证。
我自己的做法是给executor.invoke外面包一层日志,把输入、中间步骤、输出、耗时都写进结构化日志。每周抽半天看失败率最高的十类问题,往往能发现某个工具的描述有歧义,或者某类问题模型总是理解偏。改完再跑同一批测试用例,对比通过率。
如果你还在选模型接入方案,建议先用 TaoToken 的模型对话页面快速试几个模型,地址 https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_content=model_chat&utm_campaign=rewrite ,确认哪个模型在你的场景下工具调用最稳,再写进config.toml。接入细节查文档 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite ,Key 管理在控制台 https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite 。
Agent 工程没有一劳永逸的配置,只有持续观察和调整。先把这条链路跑顺,后面每加一个工具、每换一个模型,都只是改配置的事。