ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

AI Agent自主运行实战:内部积分系统与动态编排

AI Agent自主运行实战:内部积分系统与动态编排 最近在技术社区看到一个很有意思的讨论标题就叫“AI发行货币自己付费自主繁衍我们该怎么做”。乍一听有点科幻味道但拆开来看这其实是当前AI工程实践里一个非常现实的方向怎么让AI Agent具备自主完成任务、自动管理资源成本、甚至按需派生新Agent协同工作的能力。很多朋友在本地部署大模型、做AI应用开发时已经走到“模型能对话”这一步但离“系统能自己运转”还差很远。这篇文章就从这个角度出发把标题里的“发行货币”理解为内部任务积分与配额管理把“自己付费”落地为API成本核算与自动结算把“自主繁衍”落到Agent编排与自我迭代上。下文会完整讲清楚设计思路、核心组件、实操步骤和避坑经验适合正在做AI应用开发、AI Agent相关项目的工程师以及想把大模型真正用起来的技术团队参考。1. 标题背后的真实含义与技术拆解1.1 “发行货币”不是印钞而是定义资源单位很多非技术朋友听到“AI发行货币”第一反应是数字货币、挖矿之类的东西实际上在工程实践里这指的是一个内部计价体系。我们的AI应用在运行时会消耗真实成本——OpenAI、Claude、国产大模型接口都按token计费自部署的模型则占用GPU算力。为了让Agent在自主执行任务时不会“无脑花钱”必须给系统设计一套内部资源单位比如“任务积分”“算力额度”“token配额”。这套内部货币系统的作用其实和游戏里的体力值、企业里的预算池非常像。管理员给系统设定一个总预算Agent在执行任务前先估算消耗任务执行中按实际用量扣费任务完成后沉淀一份费用报告。这样一来“AI发行货币”本质上就是一套计量与配额引擎。货币本身是虚拟的但它映射到真实的API账单或算力开销上让机器行为有了成本约束也让我们能精准掌握每笔自动化操作的投入产出。在设计上这套内部货币可以细分为两个层级。第一层是“账户层”每类业务或者每个客户对应一个账户账户有余额上限、日消耗上限、单任务上限。第二层是“计量层”记录每一次大模型调用的输入token、输出token、推理耗时、附加工具调用次数然后换算成统一积分。核算逻辑要放在网关层也就是所有请求进出的必经之地这样才能保证没有任何一次调用能绕过计费。1.2 “自己付费”的核心是自动成本核算和预算保护所谓“自己付费”是指在Agent的自主工作流中系统会自动从任务账户里扣除本次操作的费用不需要人工审批。听起来简单真正做到稳定其实需要三块能力。第一块是实时计价因为大模型接口的计费规则很细不同模型、不同上下文长度、是否开启缓存价格都不一样。第二块是预算保护防止Agent在循环调用、异常重试中把预算耗尽这需要熔断机制和告警机制。第三块是费用账单回溯每个任务完成后能生成一份“钱花在哪了”的明细供我们事后分析优化。这里有个很容易忽略的细节大模型调用的实际费用往往在请求完成后才知道因为输出token是流式生成的。所以在做预算校验时不能只做“请求前预检”还必须做“请求中监控”。我们可以在网关层实时累计已产生的token消耗一旦发现某次请求的累计费用已经超过当前账户余额就主动中断生成返回一个“预算不足”的错误码而不是放任模型把整个长文生成完。1.3 “自主繁衍”其实是Agent的动态编排与自我迭代“自主繁衍”这个词最有迷惑性但落到工程上就是三件非常具体的事Agent的按需创建、任务的动态分发、经验知识的自动沉淀。当业务系统收到一批任务时一个单一的Agent往往忙不过来或者专业能力不够这时候编排器会根据任务类型动态创建多个子Agent是典型的“按需繁衍”。子Agent可以是同一套提示词的不同实例也可以是挂了不同知识库、不同工具集的专业角色。更进一步系统还可以具备“自我迭代”能力。比如某个Agent在处理一类任务时频繁出错系统会记录失败案例定期触发一次“自我复盘”把失败样本汇总分析是提示词不清晰、模型能力不足还是外部工具异常然后自动调整提示词或路由策略。这就是一种有限度的自主进化一次跑通之后后续同类任务的成功率会明显提升。把这三层拆开整个系统其实就是一个“预算管理引擎 Agent运行时 编排调度器 知识反馈回路”的组合体。下面我按实际落地顺序逐个环节讲清楚怎么做。2. 核心方案选型与设计原则2.1 大模型接入层API与本地部署如何取舍构建这套自运行系统第一步是确定用哪类大模型。如果追求效果稳定、开发速度快闭源API是首选OpenAI、Claude、国产的智谱、通义、文心等都很成熟。如果对数据安全要求高、或者长期使用的调用量非常大那就必须做本地部署。本地部署的常见方案是拿vLLM、TGI这类的推理框架搭载Qwen、DeepSeek等开源模型用一张或几张N卡就能跑起来。两者的成本结构差异很大。API模式是显性成本每次调用都有清晰的账目适合我们这套内部货币系统对接。本地部署是隐性成本GPU电费、机器折旧、运维人力都要算进去但单次推理成本在大规模调用下会迅速摊薄。我个人的建议是初期先把API跑通整个链路验证业务逻辑没问题后再逐步把高频调用的部分迁移到本地模型形成“快模型走API、重模型走本地”的混合路由。技术选型上跟大模型交互的SDK我推荐LangChain、LlamaIndex这类成熟框架但从成本控制角度更建议用标准OpenAI兼容接口自己做一层封装。原因很简单SDK出问题会影响整个链路而且很多热门框架对计费这块根本没做设计。我们自己封装的话只需要处理一个统一的/v1/chat/completions接口请求体加上用户标识和任务标识响应统一走流式这样后续接计费网关会非常顺手。2.2 Agent运行时单Agent、多Agent还是自主繁衍Agent运行时的设计直接影响整个系统的上限。最基础的是单Agent模式一个系统提示词配几个工具函数处理简单重复的任务。往上走就是固定多Agent模式比如一个主管Agent负责任务拆分两个执行Agent分别处理文本和数据处理这种结构适合业务稳定的场景。到最复杂的是动态Agent模式也就是接近“自主繁衍”的形态——编排器根据任务负载和类型实时创建新的Agent实例任务完成后自动销毁。从工程稳定性考虑我强烈建议不要一上来就做动态Agent。先把单Agent跑通把工具调用、计费闭环、异常重试做扎实再慢慢扩展成多Agent。因为动态创建Agent涉及的变量太多新Agent的能力是否可靠、任务分配是否均衡、创建和销毁的额外开销怎么算这些在缺乏基线数据的情况下很容易失控。实际项目里我们通常在最外层用一个动态编排器但每个子Agent内部仍然是高度结构化的固定流程。2.3 工具与协议MCP、函数调用和自动化平台Agent要完成真正的工作不能只靠模型本身还得会调用外部工具。当前最值得关注的是MCPModel Context Protocol协议它相当于给Agent们定义了一个统一USB接口让模型可以标准方式连接数据库、文件系统、API服务。MCP的价值在于它把工具调用从“每家自己写一套”变成了“一套协议通用”Agent生态里的工具可以复用开发成本显著降低。同时经典函数调用能力也不能丢。通过JSON Schema定义工具的参数格式让模型在对话中自动发起工具调用这种方式简单直接适合已经成熟的场景。二选一还是结合用取决于团队的技术栈。我们的经验是涉及多系统协作时用MCP单系统内部的格式化操作直接用函数调用混合使用效率最高。自动化平台方面n8n、Dify、Coze这类工具非常适合做快速原型。尤其是Dify这类支持可视化编排平台内置了Agent节点、知识库、工具调用能力我们可以在平台上先拖出整个流程验证逻辑通了之后再逐步把核心模块拆出来用代码定制。3. 完整实操从零构建一套Agent自运行系统3.1 搭建基础的本地模型推理服务下面我从零开始实操一遍以本地部署模型为例因为这条路径踩坑最多也最能体现问题的本质。假设机器上已经装好了Python 3.10、CUDA和PyTorch首先安装vLLM这个高性能推理框架。vLLM支持OpenAI兼容的API格式这对接下来的计费网关集成非常方便。pip install vllm启动模型服务的命令很简单以Qwen2.5-7B-Instruct为例python -m vllm.entrypoints.openai.api_server \ --model Qwen/Qwen2.5-7B-Instruct \ --served-model-name qwen25-7b \ --tensor-parallel-size 1 \ --max-model-len 8192 \ --port 8000启动后可以用一个最简单的请求验证服务是否正常同时这也是我们整个系统的基座curl http://localhost:8000/v1/chat/completions \ -H Content-Type: application/json \ -d { model: qwen25-7b, messages: [{role: user, content: 你好}], stream: true }这里有几个关键参数要说明。--tensor-parallel-size表示使用几张GPU并行推理显存不够时不能硬开否则会报GPU内存分配失败。--max-model-len限制上下文长度7B模型一般建议设4096或8192数值越大占用的KV Cache显存越多如果并发量大需要相应缩小。--served-model-name是给外部请求看的别名后续网关统一用这个别名做路由。如果机器配置一般也可以用Ollama这种更轻量的方案一条命令就能跑起来。但vLLM的吞吐量在并发场景下优势明显所以长期做服务化部署我更推荐vLLM。实际测试下来单张A100上跑Qwen2.5-7B并发32吞吐能到每秒2000 token以上足够支撑一个小规模业务系统了。3.2 用Python实现内部积分系统大模型底座Ready之后我们来写系统的核心——内部积分系统。这个模块负责“发行货币”也就是把模型消耗转换成可计数的积分。我用Python写一个简化版本核心数据结构就三块账户表、计价规则、流水账。# token_bank.py import time import uuid from dataclasses import dataclass, field # 计价规则按模型名区分单价这里以“积分/token”为单位 PRICING { qwen25-7b: {input: 0.0001, output: 0.0003}, # 示例数值 gpt-4o: {input: 0.001, output: 0.002}, deepseek-v3: {input: 0.0002, output: 0.0008}, } dataclass class Account: account_id: str balance: float # 剩余积分 daily_limit: float # 日消耗上限 used_today: float 0.0 last_reset_day: str def check_and_deduct(self, amount: float) - bool: 校验余额并扣款返回是否成功 if self.balance amount: return False if self.used_today amount self.daily_limit: return False self.balance - amount self.used_today amount return True def reset_daily_if_needed(self): today time.strftime(%Y-%m-%d) if self.last_reset_day ! today: self.used_today 0.0 self.last_reset_day today class TokenBank: def __init__(self): self.accounts {} self.ledger [] def create_account(self, account_id: str, initial_balance: float, daily_limit: float): self.accounts[account_id] Account( account_idaccount_id, balanceinitial_balance, daily_limitdaily_limit, ) return account_id def charge(self, account_id: str, model: str, input_tokens: int, output_tokens: int) - dict: 根据模型和token用量计算积分并扣款返回消费记录 if model not in PRICING: raise ValueError(fmodel {model} not supported) amount ( input_tokens * PRICING[model][input] output_tokens * PRICING[model][output] ) account self.accounts[account_id] account.reset_daily_if_needed() ok account.check_and_deduct(amount) record { id: uuid.uuid4().hex, account_id: account_id, model: model, input_tokens: input_tokens, output_tokens: output_tokens, amount: amount, ts: time.time(), status: ok if ok else rejected, } self.ledger.append(record) return record这段代码的关键点在于它把“发行货币”变成了一个可审计的记账过程。每次调用大模型后我们只需要告诉TokenBank三个信息——账户ID、模型名、输入输出token数它就能计算积分并扣款。如果余额不足或超过日限系统会拒绝这次推理请求Agent拿到的就不是模型输出而是一段“预算不足”的异常信息。实际部署时TokenBank里的账户和流水表必然要落到数据库我一般用MySQL存流水、Redis做热点余额缓存避免频繁写库拖慢在线推理链路。计价规则也不建议硬编码到代码里而是放到配置中心这样模型调价时不用重启服务。再加一层管理后台运营同学可以直接给客户账户充值、调整日限额、看消费报表这就跟真实的“发币付费”闭环对上了。3.3 网关层拦截请求并完成计费积分系统本身只是记账真正让每一笔调用都不漏算的是网关层。我们可以在模型服务前面加一个Python进程用FastAPI做一个反向代理。这个网关接收Agent发来的聊天请求先从请求头里解析出account_id和task_id再从本地缓存读取账户信息接着把请求转发给vLLM或远端API使用流式模式接收响应与此同时边转发给客户端边累积token计数最终把实际用量上报给TokenBank结算。# gateway.py import httpx from fastapi import FastAPI, Request app FastAPI() UPSTREAM_URL http://localhost:8000/v1/chat/completions async def forward_and_charge(account_id: str, task_id: str, payload: dict): input_token_estimate len(payload.get(messages, [])) async with httpx.AsyncClient(timeout300) as client: async with client.stream(POST, UPSTREAM_URL, jsonpayload) as resp: async for line in resp.aiter_lines(): # 这里可以用tiktoken或模型自带tokenizer统计实时token数 yield line # 流结束触发计费 # charge(account_id, model, input_cnt, output_cnt) app.post(/v1/chat/completions) async def chat_completion(request: Request): payload await request.json() account_id request.headers.get(X-Account-Id, default) task_id request.headers.get(X-Task-Id, unknown) async for line in forward_and_charge(account_id, task_id, payload): yield fdata: {line}\n\n这个代理设计带来的直接好处是所有业务方都无需关心计费逻辑只需要在请求头里带上账户标识即可。新接入一个业务Agent的时候只需要给它分配一个账户不用改一行业务代码。网关层还可以顺手做限流、模型路由、敏感信息脱敏等横切能力算是一举多得。这里有一个性能细节需要注意流式转发时不要对每一行都做数据库同步写操作否则会在高并发下把数据库连接池打满。我们一般把token计数累加在内存里每隔1秒或者累计50条才批量上报一次。计费不一定要求实时精确到每一行只要最终总额准确即可。如果某个任务中途被用户中断也要把已经消耗的token报送上去这部分不能丢。3.4 实现Agent的任务感知与自动预算分配计费链路完成后我们把注意力放到Agent本身。要让Agent具备“自己付费”意识核心是在系统提示词里嵌入当前账户的预算状态同时把计费信息以可读的形式反馈给模型。比如系统提示词可以这样写你是一个任务执行Agent。 当前账户剩余积分8500 本次任务最高可用积分2000 请在执行过程中控制调用次数和输出长度。 如果单次工具调用可能消耗大量token请先说明计划再执行。这看起来只是提示词技巧实际上意义很大模型会在决策时把“成本”纳入考量避免一上来就做无意义的长输出。除了提示词更硬性的约束在代码侧。Agent在执行任务拆分时会先向编排器申请一个子任务的预算额度假如复杂任务分成5步就让每步有一个独立的费用上限。某一步超额就停止该步的递归尝试直接返回“步骤超预算需要人工介入”。工具调用也要计入成本。很多Agent框架默认工具调用的token消耗是隐藏的但在我们的体系里一次工具调用包含模型生成工具参数输出token、工具执行返回结果作为下一轮的输入token。这两个都要计入成本。所以我们在工具调用函数里也要加上计量埋点记录工具名称、参数大小、返回结果大小这才能反映真实的资源消耗。下面是一个简单的Agent任务执行器示例它会在循环中检查当前任务是否还剩余预算# agent_runner.py class TaskAgent: def __init__(self, bank: TokenBank, account_id: str, task_budget: float): self.bank bank self.account_id account_id self.task_budget task_budget self.total_spent 0.0 def call_llm(self, messages, modelqwen25-7b): # 预检 estimate len(str(messages)) * 0.002 if self.total_spent estimate self.task_budget: return {error: task_budget_exceeded, spent: self.total_spent} # 真正调用网关 # ... 得到input_tokens, output_tokens # 计费 record self.bank.charge(self.account_id, model, input_tokens, output_tokens) self.total_spent record[amount] return {result: content, spent: record[amount]} def run(self, task: str): messages [ {role: system, content: 你是一个任务执行Agent请逐步完成任务。}, {role: user, content: task}, ] while True: resp self.call_llm(messages) if error in resp: return resp # 解析模型输出检查是否要调用工具 if need_tool_call(resp[result]): tool_res execute_tool(resp[result]) messages.append({role: assistant, content: resp[result]}) messages.append({role: tool, content: tool_res}) continue return resp[result]执行器里每一轮循环都是“模型推理→工具调用→模型推理”每次调用都先做预算估算再做真实扣费。实践中如果任务包含大量读取本地文件、处理长文本的操作token消耗会上升得非常快所以在每轮循环开头打印一下total_spent对及时发现失控任务非常有用。3.5 动态创建子Agent的编排器设计单Agent跑通之后我们开始设计“自主繁衍”的编排层。编排器接收一个高层任务比如“分析近30天销售数据并生成周报”它会执行如下逻辑先判断这个任务需要哪几个子能力比如数据提取、数据分析、文本生成然后为每个子能力创建一个子Agent实例分配独立的账户额度接着把各个子Agent的输出汇总给一个汇总Agent最后所有子Agent执行完毕释放资源。# orchestrator.py class Orchestrator: def __init__(self, bank: TokenBank, agent_factory): self.bank bank self.agent_factory agent_factory def decompose(self, task: str) - list[str]: # 先用调度模型做任务拆解 plan call_router_llm(task) return plan[subtasks] def run(self, task: str, parent_account: str): subtasks self.decompose(task) budget_per_task self.bank.accounts[parent_account].balance / (len(subtasks) 1) results [] for i, st in enumerate(subtasks): # 为子任务创建新账户相当于一次“繁衍” sub_account self.bank.create_account( f{parent_account}-sub{i}, initial_balancebudget_per_task, daily_limitbudget_per_task * 2, ) agent self.agent_factory.create(st, sub_account) result agent.run(st) results.append(result) # 汇总结果 return self.summarize(results)这段代码是“自主繁衍”的最小实现。每个子任务都拿到了一个独立账户用完即止不会相互干扰。更重要的是这种方式天然支持并行各个子Agent之间没有共享状态可以在线程池或消息队列里并发执行执行速度成倍提升。产生的账户都会记录在TokenBank的账户表里我们随时能看到某个业务一共派生过多少个临时Agent每个临时Agent花了多少积分完全是可审计的。实际项目里子Agent之间的依赖关系往往不是线性的而是构成一张DAG图。更复杂的编排器应该支持按依赖拓扑调度任务只有上游子任务完成后才创建下游子Agent。这时候可以把每个子任务封装成一个消息用Redis Stream或Kafka传递调度指令执行器组消费消息并跑Agent。3.6 自主迭代失败复盘与提示词优化“自主繁衍”做完后我们来处理“自我进化”这层。系统光能创建子Agent还不够要想越用越聪明得把失败经验回流到Agent配置里。具体做法是建一个失败案例库每当Agent任务失败或结果评分低于阈值就把现场的完整对话、工具调用记录、费用消耗写入案例库。每天晚上定时触发一次优化任务让一个专门的“复盘Agent”分析这批失败案例输出优化建议包括提示词调整、工具调用顺序调整、任务拆解方式改进等等。比如一个文本总结Agent经常在输入长文时漏掉重要数据点复盘Agent会分析出“应该增加一步先提取关键数据实体、再做总结”然后自动把这个步骤写回系统提示词模板。这里要注意的是不要让AI直接大范围改写提示词那样容易改坏。我们的做法是只允许在预置的提示词模板槽位里做局部替换而且要保留历史版本任何一次自动优化出问题都能快速回滚。“自我进化”还有一个更实际的方向知识库的自动沉淀。每次Agent成功解决一个特殊问题系统可以把这次的成功方案转化为一条高压缩的“经验片段”写入向量知识库。后续再遇到相似任务检索器会先把这些经验片段拉出来放进Agent的上下文窗口里让Agent直接参考历史成功路径能省不少token也明显提升成功率。4. 常见问题与排查技巧实录4.1 model参数不匹配导致请求失败用vLLM部署时最容易犯的错是请求体里的model名字和启动参数对不上。启动时用了--served-model-name qwen25-7b请求里写成了qwen2.5-7b网关转发过去后直接报错。排查方法是直接curl模型服务如果curl能通、网关不通多半是参数名问题。建议在网关层做一层model名字映射把对外暴露的模型名统一解析成内部服务的真实模型名。4.2 流式计费的token统计严重偏差流式模式下token是分批从模型端返回的如果用整段文本累加长度来估算误差会很大。我建议直接用模型的tokenizer离线计算每个分片的新增token量。对OpenAI兼容接口来说最简单的方案是用tiktoken库对本地Qwen这类模型则用transformers里对应的tokenizer。实测下来这类计数方法的误差能控制在1%以内足以支撑准确的积分结算。4.3 Agent陷入死循环导致预算耗尽这是所有自运行系统最怕的故障。Agent在工具调用失败后可能会反复重试同一个动作每次都产生新的模型调用如果不设上限几分钟内就能把一个账户的余额烧光。针对这个问题我在执行器里强制加了三个防御单任务最大循环次数上限如10次、相同工具连续失败上限如3次、单任务Token单价上限。任何一条触发任务立即终止并标记为“异常中”。很多线上事故都是因为缺少这种“保险丝”大家一定要提前加好。4.4 本地部署显存不足导致推理中断本地部署Agent系统显存是关键瓶颈。并发高的时候LLM推理服务和嵌入模型、重排模型抢显存很容易触发OOM。我们的经验是单独拆分服务主对话模型用vLLM独占主要显存嵌入模型用小显存碎片部署或者干脆用CPU跑Embedding。还要把vLLM的--gpu-memory-utilization参数调低一些比如0.85留出15%的显存给其他进程。实测这样配置后系统稳定性显著提升很少再出现推理进程被杀掉的情况。4.5 提示词里的预算状态引发理解混乱预算状态直接塞进系统提示词有时候模型会把“剩余积分8500”当成业务数据写进回复里造成客户困惑。解决方法是把预算信息放在“系统内部字段”中并在生成回复前的后处理阶段把预算相关内容从模型输出里剥离。具体实现是约定好分隔符比如budget.../budget模型看到这部分只做参考不得输出到最终结果。后处理时用正则直接删掉这个字段保证对外内容干净。5. 落地效果与扩展方向这套系统在我们团队内部已经稳定运行了一段时间单日处理上千个自动化任务没有出现一次预算超支事故。最大的感受是把“成本”变成Agent的硬约束之后模型的输出行为明显更克制、更务实了。过去用大模型做数据分析和报告生成经常出现几百行冗余内容接入积分系统后模型会在关键结论处收着写输出质量反而提升了。后续的扩展方向一个是把内部积分规则做得更细比如按任务的业务价值动态调整优先级高价值任务可以申请追加预算低价值任务执行压缩模式。另一个方向是完善Agent之间的协作机制让子Agent可以通过消息总线互相传递中间结果而不只是汇总给顶层Agent。再有就是加大“自主进化”的比重让复盘Agent不只是调提示词还能自动选择、切换不同规格的大模型根据任务难度匹配最合适的模型档位进一步降低综合成本。在实际操作中碰到过很多意想不到的小问题比如子Agent并发执行时账户ID生成冲突、请求重试导致重复计费、模型偶尔返回非法JSON导致工具调用中断——这些都需要在工程上一个个磨。如果大家也在做类似的AI Agent项目建议从最小闭环开始先让自己公司的某个内部流程跑通再谈宏大的自主繁衍。系统规模越大稳定性设计越要提前等出了问题再补代价会大得多。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进