1. 从聊天机器人到 Agent差的不只是几个工具很多人第一次接触 Agent 这个概念时会觉得它和聊天机器人差不多——不就是问一句答一句吗我一开始也这么想直到真正动手搭了一个才发现两者之间隔着一整套「思考-行动-观察」的循环机制。聊天机器人的工作模式是你给一段文字它回一段文字结束。它不会主动去查资料不会调用计算器更不会在发现自己答错后重新规划。而 Agent 的核心区别在于它能自己决定「下一步该干什么」——是先搜索一下最新数据还是直接调用某个 API或者干脆承认信息不足需要追问。这个决策过程就是 ReActReasoning Acting循环要解决的问题。这篇内容面向的是想从零跑通第一个 Agent 原型的开发者。你不需要有 LangChain 深度使用经验但最好写过 Python、调过至少一个 LLM 的 API。我会用一个统一的 Key 来打通 LLM 推理和工具调用两条通道避免在多个平台之间来回切换 Key 和配置。整个链路拆成四块环境准备、Agent 骨架配置、ReAct 循环实现、一次完整的验证请求。跟着走一遍你能得到一个能自主决定「要不要调工具、调哪个工具」的最小可用 Agent。2. 前置准备用 TaoToken 统一 Key 打通 LLM 与工具通道搭 Agent 最烦的事情之一是 LLM 一个 Key、搜索工具一个 Key、代码执行环境又一个 Key配置散落在四五个地方调试的时候光找 Key 就耗掉一半耐心。我试过把不同供应商的 Key 写在一个.env里结果每次换模型都要改代码里的 base_url 和 model 名非常容易出错。TaoToken 在这里的作用是提供一个统一的接入层LLM 推理请求走同一个 API 地址工具调用通道也通过同一套 Key 体系管理。你只需要在settings.json里维护一份配置Agent 的推理模块和工具模块都从这里读。先拿到 Key。访问控制台创建 API Keyhttps://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite创建完成后你会得到一个以sk-开头的字符串。把它存到环境变量里不要硬编码进代码export TAOTOKEN_API_KEYsk-你的key如果你用的是 Claude Code 或类似的编码 Agent 工具可以直接参考接入文档里的配置方式https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewriteAPI 的基础地址是https://taotoken.net/api注意这个地址不带 UTM 参数直接用于代码里的base_url配置。官网入口在这里https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content3. 可复制配置Agent 骨架的 settings.json 片段Agent 的骨架配置需要解决三件事LLM 怎么调、工具怎么注册、ReAct 循环的提示词模板长什么样。下面这份settings.json可以直接复制使用把 Key 的部分替换成你自己的。{ llm: { base_url: https://taotoken.net/api, api_key_env: TAOTOKEN_API_KEY, model: claude-sonnet-4-20250514, max_tokens: 2048, temperature: 0.3 }, tools: { search_web: { enabled: true, description: 搜索互联网获取实时信息输入为搜索关键词字符串, endpoint: https://taotoken.net/api/tools/search, api_key_env: TAOTOKEN_API_KEY }, run_python: { enabled: true, description: 执行 Python 代码片段输入为可运行的代码字符串, endpoint: https://taotoken.net/api/tools/code, api_key_env: TAOTOKEN_API_KEY } }, agent: { max_iterations: 6, stop_sequence: Final Answer:, prompt_template: react_v1 } }几个关键参数说明一下。max_iterations控制 ReAct 循环最多跑几轮设成 6 是防止 Agent 陷入无限思考——我踩过的坑就是没设上限结果模型在「搜索-发现不够-再搜索」之间循环了十几次Token 消耗直接起飞。temperature设 0.3 是因为 Agent 需要稳定的决策太高的随机性会让它频繁选错工具。stop_sequence用来告诉模型什么时候该输出最终答案而不是继续调工具。工具注册部分每个工具需要提供description这段文字会直接拼进 Prompt 里模型靠它来判断该不该调用这个工具。描述写得越清楚工具选择越准确。比如「搜索互联网获取实时信息」就比「搜索工具」好得多。Prompt 模板单独放在一个文件里核心结构是这样的REACT_PROMPT 你是一个可以使用工具的智能助手。请严格按照以下格式回应 Question: 用户的问题 Thought: 你需要思考当前该做什么 Action: 要调用的工具名必须是 [{tool_names}] 中的一个 Action Input: 传给工具的输入 Observation: 工具返回的结果 ...Thought/Action/Action Input/Observation 可以重复多次 Thought: 我现在知道最终答案了 Final Answer: 对用户问题的最终回答 可用工具 {tools} 开始 Question: {input} {agent_scratchpad}agent_scratchpad是循环过程中不断累积的中间步骤每次调用 LLM 时把之前的 Thought-Action-Observation 记录拼进去模型就能基于历史决定下一步。4. 实现 ReAct 循环从 Thought 到 Observation 的完整代码配置就绪后核心逻辑就是一个 while 循环。下面这段代码实现了完整的 ReAct 流程可以直接跑import os import json import re import requests with open(settings.json) as f: config json.load(f) API_KEY os.environ[config[llm][api_key_env]] BASE_URL config[llm][base_url] def call_llm(prompt: str) - str: resp requests.post( f{BASE_URL}/v1/messages, headers{ x-api-key: API_KEY, anthropic-version: 2023-06-01, content-type: application/json }, json{ model: config[llm][model], max_tokens: config[llm][max_tokens], temperature: config[llm][temperature], messages: [{role: user, content: prompt}] } ) resp.raise_for_status() return resp.json()[content][0][text] def execute_tool(tool_name: str, tool_input: str) - str: tool_cfg config[tools].get(tool_name) if not tool_cfg or not tool_cfg[enabled]: return f错误工具 {tool_name} 未注册或未启用 resp requests.post( tool_cfg[endpoint], headers{Authorization: fBearer {API_KEY}}, json{input: tool_input} ) resp.raise_for_status() return resp.json().get(output, 工具返回为空) def run_agent(user_input: str) - str: tool_names [k for k, v in config[tools].items() if v[enabled]] tool_descs \n.join( f- {k}: {v[description]} for k, v in config[tools].items() if v[enabled] ) scratchpad for i in range(config[agent][max_iterations]): prompt REACT_PROMPT.format( toolstool_descs, tool_names, .join(tool_names), inputuser_input, agent_scratchpadscratchpad ) output call_llm(prompt) if Final Answer: in output: return output.split(Final Answer:)[-1].strip() action_match re.search(rAction:\s*(\w), output) input_match re.search(rAction Input:\s*(.), output) if not action_match or not input_match: scratchpad output \nObservation: 格式错误请按 Thought/Action/Action Input 格式输出\n continue tool_name action_match.group(1).strip() tool_input input_match.group(1).strip() observation execute_tool(tool_name, tool_input) scratchpad f{output}\nObservation: {observation}\n return 达到最大迭代次数未能得出最终答案这段代码的关键点在于scratchpad的累积方式。每次循环把模型输出的 Thought 和 Action、以及工具返回的 Observation 拼接到一起下一轮再喂回去。模型看到「我之前搜了什么、得到了什么结果」就能判断是继续调工具还是给出最终答案。execute_tool里做了工具名的校验如果模型输出了一个不存在的工具名会返回错误信息而不是直接崩溃。这个错误信息也会进入 Observation模型看到后通常会修正自己的选择。5. 验证请求一次完整的 Thought-Action-Observation 流程配置和代码都就位后跑一个真实请求来验证整条链路。用下面这个调用result run_agent(帮我查一下 2025 年诺贝尔物理学奖颁给了谁并计算获奖者人数乘以 100 万) print(result)预期会看到类似这样的中间过程实际输出取决于模型和工具返回Thought: 这个问题需要两步先搜索诺贝尔物理学奖信息再做乘法计算。 Action: search_web Action Input: 2025 诺贝尔物理学奖 获奖者 Observation: 2025 年诺贝尔物理学奖授予 John Clarke、Michel Devoret 和 John Martinis... Thought: 我找到了 3 位获奖者现在需要计算 3 * 1000000。 Action: run_python Action Input: print(3 * 1000000) Observation: 3000000 Thought: 我现在知道最终答案了。 Final Answer: 2025 年诺贝尔物理学奖授予 3 位科学家获奖者人数乘以 100 万等于 3000000。这个流程完整展示了 ReAct 的三个阶段Thought 是模型的推理Action 是它选择的工具Observation 是工具返回的结果。模型在第一轮判断需要搜索第二轮判断需要计算第三轮确认信息足够后输出最终答案。如果你想单独验证模型对话通道是否正常可以用模型对话入口快速测一下https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite如果 Agent 需要长期运行、频繁调用工具建议看一下 Coding Plan 的额度方案https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite6. 本篇常见错排查报错一KeyError: TAOTOKEN_API_KEY环境变量没设置或者设置在了错误的 shell 会话里。检查echo $TAOTOKEN_API_KEY是否有输出。如果是在 IDE 里运行需要在运行配置里单独加环境变量而不是只在终端 export。报错二模型一直输出 Action 但不输出 Final Answer通常是 Prompt 模板里的stop_sequence没生效或者max_iterations设得太小。先检查模板里是否明确写了「如果信息足够输出 Final Answer」。另一个可能是工具返回的 Observation 太长把上下文撑满了模型看不到完整历史。可以在execute_tool里对返回结果做截断比如只保留前 500 字符。报错三工具调用返回 401工具通道的 Key 和 LLM 通道的 Key 不一致。检查settings.json里工具的api_key_env是否指向了同一个环境变量。如果工具端点是外部服务确认该服务的鉴权方式是不是 Bearer Token。报错四ReAct 循环卡在同一个工具上反复调用模型没有正确解析 Observation。检查execute_tool返回的内容是否包含换行符或特殊字符这些可能干扰模型对格式的解析。建议在 Observation 前后加明确的分隔标记比如[OBSERVATION_START]...[OBSERVATION_END]。报错五requests.exceptions.SSLError本地 Python 环境的证书链有问题。可以临时用verifyFalse跳过验证来确认是否是证书问题但生产环境不要这么做。正确的做法是更新certifi包pip install --upgrade certifi。排查完这些之后如果还有接入层面的问题可以对照接入文档里的示例请求逐项检查https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite7. 下一步从原型到可用 Agent 的迭代方向跑通上面这个最小原型后你手里已经有一个能自主决策的 Agent 了。接下来可以按需加东西加一个向量数据库做长期记忆让 Agent 记住跨会话的信息把工具从两个扩展到五六个覆盖搜索、计算、文件读写、API 调用优化 Prompt 模板加入 Few-shot 示例来提升工具选择的准确率。但别一上来就堆功能。我的建议是先把当前这个版本跑稳用十几个不同的问题测一遍观察它在哪些情况下会选错工具、哪些情况下会陷入循环。把这些边界情况摸清楚之后再针对性地加工具和改 Prompt比盲目扩展要有效得多。
企业数字化 ERP 产品动态
相关推荐
Win11向日葵闪退根因:AweSunService延迟启动超时解析 1. 问题现场还原:不是软件崩溃,是服务“装睡”我第一次遇到这个现象时,以为是向日葵客户端本身出了毛病。双击桌面图标——屏幕闪一下,任务栏图标刚冒个头就消失,进程管理器里根本找不到SunloginClient.exe的影子&… · 2026/9/26 18:03:02
Java多线程与并发编程:从JMM到线程池的实战指南 Java多线程与并发,这个话题在面试和实战里被翻来覆去地问、反反复复地踩。很多人背了一堆八股文,从Thread到ThreadPoolExecutor,从synchronized到Lock,看似什么都懂,真到了线上排查问题、设计一个高并发接口的时候&… · 2026/9/26 18:03:02
Java多线程与并发编程实战:从JMM原理到高并发系统优化 做了这么多年Java开发,面试过别人也被别人面过,多线程与并发永远是最绕不开的一块。往浅了问是new Thread().start()和Runnable接口,往深了问是AQS、CAS、内存可见性,中间还夹着线程池参数、锁升级、并发容器,随便拎一… · 2026/9/26 18:03:02
Windows安装Milvus完整指南:WSL2+Docker避坑实战 1. 为什么在 Windows 上装 Milvus 是个“看似简单、实则踩坑密集”的活儿Milvus 这个名字,现在但凡碰过向量检索、AI 应用、RAG 构建或者大模型本地知识库的人,基本都绕不开。它不是传统意义上的数据库,而是一个专为高维向量相似性搜索设计的… · 2026/9/27 0:15:21
基于Java自研零代码可视化编排引擎:架构设计与核心实现 零代码和可视化编排最近在 Java 圈子里确实火,但市面上能直接落地的开源方案并不多。自己动手基于 Java 生态搭一个,听起来工程量很大,实际上把核心思路理清楚后,反而比想象中简单。我当初做这个引擎,主要就是为了解决… · 2026/9/27 0:15:15
Node.js 端口冲突 EADDRINUSE:从报错机制到工程化解法 EADDRINUSE:端口冲突的临场反应我先把话说在前面:如果你正在做一个基于 Node.js 的全栈项目,不管是 Express、Koa、NestJS 还是 Next.js,只要你的开发机上同时跑着两个后端服务、一个前端 dev server、可能还有一个数据库管理面板… · 2026/9/27 0:15:15
LeetCode 1545:第N个二进制字符串第K位——递归、模拟与数学映射全解析 LeetCode 1545. 找出第 N 个二进制字符串中的第 K 位,这道题我刷第一眼觉得简单,细看才发现它把“模拟”、“递归”、“数学映射”三个层次全串在了一起。题目给了一个二进制字符串序列 Sn,规则很直白:S1 "0"ÿ… · 2026/9/27 0:15:15
c视频播放网站开发完整流程与避坑指南 c视频播放网站开发完整流程与避坑指南 改个需求建站公司拖一周,这种憋屈事谁没遇到过?明明只是换个播放器皮肤或加个倍速功能,对方却以“技术难度大”为由无限期拖延。做c视频播放网站开发,最怕的就是流程不透明,导致后期维护变成无底洞。今天不聊虚的… · 2026/9/27 0:15:01
红帽linux安装wordpress踩坑实录含源码下载避坑指南 红帽linux安装wordpress踩坑实录含源码下载避坑指南 网站被黑挂马不知道怎么办?别慌,这往往是底层环境没搭好导致的。很多站长花大价钱买模板,却忽略了红帽linux安装wordpress时的权限漏洞,最后只能被迫源码下载重写。… · 2026/9/27 0:14:49
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01