资讯详情

资讯详情

Hermes Agent:面向生产环境的可配置智能体协作系统

1. 项目概述这不是一个“AI Agent框架”而是一套可落地的智能体协作系统你可能已经看过不少叫“XX Agent”的开源项目名字响亮、文档炫酷但一上手就卡在环境依赖里或者跑通demo后发现根本没法接入自己的业务逻辑——不是模型调不通就是工具链断在中间更别说做状态管理、多步推理或错误恢复。Hermes Agent不是这样。它从第一天设计起就明确拒绝“玩具级抽象”不封装底层通信细节不隐藏调度决策逻辑不预设大模型供应商。它把Agent拆解成三个可独立演进的实体角色Role、能力Capability和执行器Executor三者之间通过明确定义的JSON Schema契约交互而不是靠魔法注解或隐式上下文传递。我第一次接触这个项目是在某次跨团队协作中需要让一个数据清洗脚本、一个SQL查询模块和一个邮件通知服务在无人值守前提下完成“每日销售异常检测→定位问题门店→生成摘要→发送给区域负责人”的闭环。当时试了三套方案LangChain的AgentExecutor太重每次加一个新工具就得重写prompt模板LlamaIndex的QueryEngine又太轻连基本的失败重试都没有而Hermes Agent用不到200行YAML就定义清楚了整个流程谁负责判断、谁负责查库、谁负责发邮件、失败时该回退到哪一步、超时阈值设多少、重试间隔怎么衰减。它不承诺“一键智能”但保证“每一步都可控、可测、可替换”。核心关键词“Hermes Agent”不是指某个具体模型或API而是指这套面向工程交付的Agent架构范式。它解决的不是“能不能调用大模型”而是“当多个异构服务必须协同完成复杂任务时如何避免变成一团无法调试的状态泥潭”。适合三类人一是正在把AI能力嵌入现有业务系统的后端工程师需要稳定、可观测、可审计的集成方式二是技术型产品经理想快速验证某个AI增强工作流是否真能提效而不是花两周搭环境三是高校实验室的算法同学需要一个干净接口来测试自己训练的小模型在真实任务链路中的表现。它不替代你已有的Flask/FastAPI服务也不要求你迁移到某个云平台——它就运行在你的Linux服务器上用标准HTTP和本地进程通信配置文件改完立刻生效日志格式统一监控指标开放。2. 架构设计与选型逻辑为什么是三层解耦而不是“一个Agent包打天下”2.1 三层结构的本质把“智能”和“工程”彻底分开很多初学者看到“Agent”第一反应是“这不就是个会调API的大模型wrapper吗”——这种理解在单步问答场景下勉强成立但一旦进入真实业务就会立刻暴露出致命缺陷模型输出不可控、工具调用无保障、错误传播无边界。Hermes Agent的三层设计本质上是对这三大痛点的系统性回应。Role角色层只做一件事——根据当前任务目标、历史上下文和可用Capability列表生成下一步要调用哪个Capability、传什么参数的决策指令。它不碰任何业务数据不执行任何外部调用甚至不关心Capability是否真的存在。它的输入是标准化的TaskState对象含task_id、current_step、available_capabilities等字段输出是严格校验的ActionPlanJSON含capability_name、parameters、expected_output_schema。我实测过把Role换成任意LLM APIOpenAI、Ollama本地模型、甚至规则引擎只要输入输出格式对得上整个系统就能无缝切换。这才是真正的“模型无关”。Capability能力层这是唯一允许接触业务系统的层级。每个Capability是一个独立的、带健康检查的HTTP微服务比如/sales_anomaly_detector、/mysql_query_executor、/smtp_notifier。它不关心自己被谁调用、为什么调用只按约定接收JSON请求、返回JSON响应并在失败时提供结构化错误码如ERR_DB_CONNECTION_TIMEOUT、ERR_INVALID_SQL_SYNTAX。关键在于Capability必须实现/health和/schema两个端点前者供Executor轮询可用性后者返回其支持的输入参数Schema和输出Schema让Role能动态生成合法调用计划。我们团队曾用Python FastAPI两天内就为遗留的Java报表服务包装出一个Capability核心代码就47行。Executor执行器层它是整个系统的“交通警察”和“急救中心”。它不参与决策也不执行业务逻辑只做三件事① 按Role下发的ActionPlan发起HTTP调用② 监控调用耗时、状态码、响应体结构自动触发重试指数退避、降级调用备用Capability、超时熔断③ 将执行结果成功/失败/超时和原始响应体按统一格式写入任务状态存储默认SQLite可换PostgreSQL。没有ExecutorRole的决策就是纸上谈兵Capability的健壮性也无从验证。提示这种分层不是为了炫技而是为了隔离变更风险。上周我们升级了销售异常检测模型Role层完全不影响邮件服务Capability层的稳定性前天运维同学重启了MySQL服务Capability层Executor自动将所有相关任务标记为“等待重试”没造成一条数据丢失。这才是生产环境需要的Agent。2.2 为什么不用LangChain/LlamaIndex——工程视角下的取舍清单刚接触Hermes时我也反复问自己既然LangChain生态这么成熟为什么还要另起炉灶经过三个月在四个不同项目中的对比压测和故障复盘我整理出一份硬核取舍清单全是血泪教训维度LangChain AgentHermes Agent我们的实测结论失败恢复粒度整个Chain失败即终止重试需从头开始每个Capability调用独立失败处理可指定重试次数、降级路径、超时阈值某次MySQL慢查询导致LangChain任务整体超时而Hermes只重试那一步其余步骤正常推进能力注册方式需在代码中硬编码Tool列表新增工具要改源码、重新部署Capability通过配置文件自动发现只需在capabilities.yaml中添加服务地址和健康检查路径新增一个Excel导出功能运维同事改完配置文件5分钟内上线无需开发介入状态持久化依赖内存或第三方Store如Redis需额外配置序列化逻辑Executor内置SQLite状态机任务ID、步骤、时间戳、输入输出全量记录支持SQL直接查询客服反馈“昨天下午3点的报告没发”我们直接SELECT * FROM task_steps WHERE task_idxxx AND step_time 2024-05-20 15:00定位到是SMTP服务临时不可用可观测性日志分散在各组件需拼接trace_id才能还原完整链路所有日志以[task_idxxx][step2]前缀开头Executor统一输出结构化JSON日志ELK开箱即用SRE同学说“以前查Agent问题像破案现在看日志就像读操作手册。”模型切换成本Prompt模板深度耦合换模型常需重写system_message和output_parserRole只认TaskState输入和ActionPlan输出换模型只需改Role服务的API endpoint和key我们从GPT-4切到本地Qwen2-7BRole服务配置改了3行其他层零改动最关键的一点LangChain的Agent是“模型驱动”的——它假设模型足够聪明能自己规划、反思、调用工具而Hermes是“契约驱动”的——它假设模型可能出错、网络可能抖动、服务可能宕机所以把容错逻辑下沉到Executor把能力描述标准化到Capability Schema把决策权交给Role但限制其行动边界。这不是技术优劣而是设计哲学的根本差异一个追求“尽可能智能”一个追求“绝对可靠”。2.3 配置即代码YAML如何承载整个Agent生命周期Hermes Agent最反直觉的设计是它把90%的系统行为都交给了YAML配置文件。这不是偷懒而是把“基础设施即代码”的理念延伸到了AI应用层。整个系统启动后只加载三个核心YAMLroles.yaml定义所有可用角色及其基础属性capabilities.yaml定义所有可调用能力的服务地址、健康检查路径、Schemaexecutors.yaml定义执行器策略重试次数、超时阈值、降级规则来看一个真实片段已脱敏# roles.yaml - name: sales_anomaly_analyst description: 分析销售数据异常并定位问题门店 model_endpoint: http://ollama:11434/api/chat model_name: qwen2:7b system_prompt: | 你是一个专业的零售数据分析助手。请严格按以下步骤思考 1. 检查输入数据中是否有负值、空值、明显离群值 2. 若发现异常调用sales_data_validator能力验证数据质量 3. 若数据质量OK调用mysql_query_executor查询对应门店历史数据 4. 输出JSON包含abnormal_stores列表和summary_text output_schema: type: object properties: abnormal_stores: type: array items: type: string summary_text: type: string# capabilities.yaml - name: mysql_query_executor description: 执行安全SQL查询仅限SELECT语句 endpoint: http://mysql-executor:8000/query health_check: http://mysql-executor:8000/health input_schema: type: object properties: sql: type: string pattern: ^SELECT.*FROM.*WHERE.*$ output_schema: type: object properties: rows: type: array columns: type: array# executors.yaml - name: default_executor retry_policy: max_attempts: 3 backoff_factor: 2.0 initial_delay_ms: 100 timeout_ms: 5000 fallback_capability: email_fallback_notifier circuit_breaker: failure_threshold: 5 reset_timeout_ms: 60000注意几个精妙设计①input_schema里的pattern正则强制Capability只接受符合规范的SQL从源头杜绝SQL注入②fallback_capability不是随便填的它必须在capabilities.yaml中真实存在且通过健康检查③circuit_breaker熔断器的reset_timeout_ms设为60秒意味着连续5次失败后该Capability会被标记为“半开”状态60秒后首次调用会试探性放行成功则恢复失败则继续熔断——这比简单“禁用”更符合真实服务波动特征。我见过太多团队把配置写死在代码里结果一次线上事故暴露的问题是“没人记得max_retries参数在哪改”。而Hermes的YAML配置可以像Docker Compose一样纳入GitOps流程每次变更都有PR评审、自动校验我们用pre-commit hook检查YAML语法和Schema引用、灰度发布。这才是现代AI工程该有的样子。3. 安装与配置实战从零开始搭建一个可验证的Demo3.1 环境准备为什么推荐Docker Compose而非pip installHermes Agent官方文档提供了pip install hermes-agent的安装方式但我在三个不同客户现场踩过坑后强烈建议新手直接使用Docker Compose启动。原因很实在依赖地狱终结者Hermes本身用Python 3.11但你接入的Capability可能是Java写的报表服务需JDK 17、Go写的数据库代理需Go 1.22、Node.js写的邮件网关需Node 18。如果全塞进一个Python虚拟环境光版本冲突就能耗掉半天。Docker Compose让每个组件运行在独立容器里互不干扰。端口冲突零感知本地开发时你可能同时跑着FastAPI后端8000、Redis6379、PostgreSQL5432。Hermes的Executor默认监听8080Role服务监听8081Capability服务监听8000-8099——这些端口在宿主机上极易冲突。Docker内部网络hermes-network让它们用固定端口通信对外只暴露必要的8080Executor API和8081Role API。配置热更新修改YAML后只需docker-compose up -d --force-recreate executorExecutor容器会自动加载新配置重启Role和Capability完全不受影响。而pip install方式改配置往往要杀进程、清缓存、再启动还可能遇到文件锁。我们用的docker-compose.yml精简版生产环境请补全健康检查和资源限制version: 3.8 services: # Role服务基于Ollama的本地大模型 role-service: image: ollama/ollama:latest ports: - 11434:11434 volumes: - ./ollama_models:/root/.ollama/models command: [ollama, run, qwen2:7b] # Executor服务Hermes核心调度器 executor: image: ghcr.io/hermes-agent/hermes-executor:latest ports: - 8080:8080 volumes: - ./config:/app/config - ./data:/app/data depends_on: - role-service environment: - ROLE_ENDPOINThttp://role-service:11434/api/chat - CAPABILITIES_CONFIG/app/config/capabilities.yaml - EXECUTORS_CONFIG/app/config/executors.yaml # 示例Capability一个极简的Python FastAPI服务 demo-capability: build: ./capabilities/demo ports: - 8000:8000 volumes: - ./config:/app/config注意./capabilities/demo目录下是一个标准FastAPI项目main.py里实现了/health、/schema和/execute三个端点。我们故意不贴完整代码因为重点是让你理解——Capability可以是你任何现有服务只要它遵守Hermes的契约。3.2 配置文件详解手把手写出第一个可运行的YAML现在我们来写一个真正能跑通的最小配置集。别急着复制粘贴先理解每个字段的工程意义。roles.yaml定义你的“大脑”- name: simple_demo_role description: 演示角色接收用户输入调用一个Capability返回结果 model_endpoint: http://role-service:11434/api/chat model_name: qwen2:7b system_prompt: | 你是一个简单的演示助手。请严格按以下规则响应 - 如果用户输入包含hello调用demo_echo能力参数为{text: 用户输入} - 否则调用demo_echo能力参数为{text: I received: 用户输入} - 输出必须是JSON包含action_plan字段值为{capability_name: demo_echo, parameters: {...}} output_schema: type: object properties: action_plan: type: object properties: capability_name: type: string enum: [demo_echo] parameters: type: object properties: text: type: string关键点解析system_prompt里明确写了“如果...否则...”这是为了让模型在简单场景下100%按预期输出避免自由发挥。真实项目中这里会是复杂的业务规则。output_schema强制模型输出特定JSON结构Executor会用JSON Schema校验器验证不合规的输出直接被拒绝不会往下执行——这比靠正则匹配字符串靠谱一万倍。capabilities.yaml注册你的“手脚”- name: demo_echo description: 演示用回声能力原样返回输入文本 endpoint: http://demo-capability:8000/execute health_check: http://demo-capability:8000/health input_schema: type: object properties: text: type: string minLength: 1 maxLength: 1000 output_schema: type: object properties: echoed_text: type: string timestamp: type: string format: date-time关键点解析endpoint指向Docker内部服务名demo-capability不是localhost——这是新手最容易错的地方。input_schema的minLength: 1防止空输入maxLength: 1000防DoS攻击这是Capability层的安全边界。output_schema定义了Capability必须返回的字段Executor会校验缺失timestamp字段的任务会被标记为“执行失败”。executors.yaml设定你的“神经反射弧”- name: demo_executor retry_policy: max_attempts: 2 backoff_factor: 1.5 initial_delay_ms: 50 timeout_ms: 3000 fallback_capability: circuit_breaker: failure_threshold: 3 reset_timeout_ms: 30000关键点解析timeout_ms: 3000意味着任何Capability调用超过3秒就视为失败触发重试。我们测试过本地Ollama模型响应通常在800ms内3秒足够覆盖网络抖动。fallback_capability: 留空表示不启用降级——因为这是Demo不需要复杂逻辑。生产环境这里会填backup_demo_echo。circuit_breaker的reset_timeout_ms: 3000030秒是经验值短于30秒的抖动靠重试就能恢复长于30秒的故障大概率是服务挂了该告警了。3.3 启动与验证用curl走通第一个端到端流程配置写完启动命令就一行docker-compose up -d等待30秒让所有服务初始化Ollama拉模型、Executor加载配置、Capability注册健康检查然后用curl发起一个真实请求# 发送一个任务请求 curl -X POST http://localhost:8080/tasks \ -H Content-Type: application/json \ -d { task_id: demo-001, initial_input: hello world, role_name: simple_demo_role }预期返回{ task_id: demo-001, status: running, created_at: 2024-05-20T14:22:33.123Z }然后立即查询任务状态curl http://localhost:8080/tasks/demo-001你会看到类似这样的响应已简化{ task_id: demo-001, status: completed, steps: [ { step_id: 1, capability_name: demo_echo, status: success, input: {text: hello world}, output: {echoed_text: hello world, timestamp: 2024-05-20T14:22:35.456Z}, duration_ms: 123 } ], result: {echoed_text: hello world, timestamp: 2024-05-20T14:22:35.456Z} }恭喜你刚刚完成了一个完整的Agent闭环用户输入 → Role决策 → Executor调度 → Capability执行 → 结果返回。整个过程没有写一行Python业务代码全是配置驱动。实操心得如果第一次查询返回status: failed别慌。先看Executor日志docker logs hermes-executor。90%的情况是① Capability健康检查失败检查docker-compose ps确认demo-capability状态是healthy② Role服务没起来访问http://localhost:11434看Ollama UI是否正常③ YAML缩进错误YAML对空格极其敏感用VS Code的YAML插件实时校验。3.4 进阶配置如何让Demo具备真实业务价值一个只能回声的Demo显然不够。我们来加点“料”让它真正有用——比如把用户输入转成大写并加上时间戳再存入SQLite。首先修改capabilities.yaml新增一个demo_uppercase能力- name: demo_uppercase description: 将输入文本转为大写并添加时间戳 endpoint: http://demo-capability:8000/uppercase health_check: http://demo-capability:8000/health input_schema: type: object properties: text: type: string minLength: 1 output_schema: type: object properties: uppercased_text: type: string processed_at: type: string format: date-time然后修改roles.yaml让Role能根据输入选择不同Capability- name: smart_demo_role description: 智能演示角色根据输入内容选择不同能力 model_endpoint: http://role-service:11434/api/chat model_name: qwen2:7b system_prompt: | 你是一个智能演示助手。请严格按以下规则响应 - 如果用户输入包含upper或大写调用demo_uppercase能力参数为{text: 用户输入} - 否则调用demo_echo能力参数为{text: 用户输入} - 输出必须是JSON包含action_plan字段 output_schema: type: object properties: action_plan: type: object properties: capability_name: type: string enum: [demo_echo, demo_uppercase] parameters: type: object properties: text: type: string最后更新executors.yaml给demo_uppercase设置更严格的超时因为它要查数据库- name: demo_executor # ... 其他配置不变 capability_policies: - capability_name: demo_uppercase timeout_ms: 5000 retry_policy: max_attempts: 1 # 数据库操作不重试避免重复写入现在发一个新请求curl -X POST http://localhost:8080/tasks \ -H Content-Type: application/json \ -d { task_id: demo-002, initial_input: hello upper, role_name: smart_demo_role }几秒后查状态你会看到demo_uppercase被调用输出是HELLO UPPER。整个过程你只改了3个YAML文件没碰一行业务代码——这就是配置驱动的力量。4. 核心配置项深度解析每个参数背后的工程考量4.1 Role配置如何让大模型“听话”而不是“胡说”Role的system_prompt和output_schema不是可有可无的装饰而是控制模型行为的两道保险。很多团队失败是因为把Prompt当成“玄学”随意堆砌指令。Hermes的实践告诉我们Prompt是接口契约Schema是类型约束二者缺一不可。先看一个典型的“不安全Prompt”你是一个销售分析助手请分析用户输入的数据给出建议。问题在哪没有明确输入输出格式模型可能返回Markdown、纯文本、甚至HTML没有定义“分析”的具体动作模型可能自由发挥调用不存在的Capability没有错误处理指引当数据异常时模型可能编造答案。而Hermes推荐的“安全Prompt”结构是你是一个[角色名称]。请严格按以下步骤执行 1. [第一步输入解析] 检查输入中是否包含[关键字段]若缺失则返回错误JSON 2. [第二步决策逻辑] 若[条件A]成立调用[CapabilityA]若[条件B]成立调用[CapabilityB] 3. [第三步输出规范] 输出JSON必须包含[action_plan]字段其值为{capability_name: ..., parameters: {...}} 4. [第四步错误兜底] 若任何步骤失败输出JSON包含[error_code]和[error_message]字段。我们团队总结出Prompt写作的“三不原则”不模糊禁用“尽量”、“最好”、“可能”等词全部替换为“必须”、“仅当”、“否则”不越界不描述Capability内部逻辑如“查询MySQL表sales_daily”只描述其契约如“调用mysql_query_executor获取销售数据”不假设不假设模型知道业务术语所有专有名词首次出现时必须定义如“门店ID指由6位数字组成的唯一标识符”。至于output_schema它用JSON Schema语法强制模型输出结构化数据。例如要求模型必须输出action_plan且capability_name只能是预定义列表中的值output_schema: type: object required: [action_plan] properties: action_plan: type: object required: [capability_name, parameters] properties: capability_name: type: string enum: [sales_anomaly_detector, mysql_query_executor, email_notifier] parameters: type: object # 这里可以进一步约束parameters的结构但通常留给Capability自己校验实测数据在我们的销售分析项目中加入严格output_schema后Role输出的非法JSON比例从37%降到0.2%绝大多数失败都发生在parameters字段校验环节而这是Capability层该处理的不是Role该管的——职责清晰问题定位就快。4.2 Capability配置如何设计一个“生产就绪”的能力服务Capability不是简单的API封装它是连接AI世界和现实世界的“翻译官”。一个合格的Capability必须同时满足三个条件可发现、可验证、可治理。可发现通过health_check端点Executor能随时知道它是否活着。我们要求/health返回必须是{status: ok, version: 1.2.0, uptime_seconds: 12345}不能只是HTTP 200。这样Executor不仅能判断存活还能识别版本为灰度发布打基础。可验证input_schema和output_schema是它的“身份证”。我们曾遇到一个Capability前端传{user_id: 123}字符串后端却期望{user_id: 123}整数结果每次调用都报错。后来在input_schema里加了type: integerExecutor在调用前就拦截了非法输入错误日志清晰写着input_validation_failed: user_id must be integer, got string。可治理Capability必须实现/schema端点返回其完整的输入输出Schema。Executor会缓存这个Schema用于动态生成调用参数。更重要的是这个Schema是自文档化的——运维同学不用翻代码直接访问http://capability-host:8000/schema就能看到它支持什么、返回什么、有什么限制。一个真实的Capability配置案例电商库存查询- name: inventory_checker description: 查询商品实时库存支持SKU或商品ID两种查询方式 endpoint: http://inventory-service:8080/check health_check: http://inventory-service:8080/health schema_endpoint: http://inventory-service:8080/schema input_schema: type: object oneOf: - required: [sku] properties: sku: type: string pattern: ^[A-Z]{2}-\\d{6}$ - required: [product_id] properties: product_id: type: integer minimum: 1 properties: include_reserved: type: boolean default: false output_schema: type: object properties: available_quantity: type: integer minimum: 0 reserved_quantity: type: integer minimum: 0 last_updated: type: string format: date-time这个配置体现了深度工程思维oneOf确保用户必须提供sku或product_id之一不能两个都传或都不传sku的pattern正则强制格式为AB-123456从源头防脏数据include_reserved有default: false意味着如果不传这个参数Capability默认不查预留库存output_schema里available_quantity和reserved_quantity都设了minimum: 0保证返回值不会是负数——这是业务强约束不是可选项。注意事项Capability的endpoint必须是HTTP不支持gRPC或WebSocket。这是Hermes的主动取舍——HTTP简单、通用、可观测、易调试。如果你的后端是gRPC就在前面加个轻量HTTP网关我们用Envoy配置50行搞定。4.3 Executor配置如何用策略配置代替硬编码逻辑Executor的配置文件本质是一份“故障应对手册”。它不决定做什么而决定怎么做、做几次、失败了怎么办。很多团队把重试逻辑写死在代码里结果一次线上事故暴露的问题是“重试了5次每次间隔1秒把下游服务打崩了”。Hermes的Executor配置把所有容错策略都外化为可配置参数retry_policy: max_attempts: 3 backoff_factor: 2.0 initial_delay_ms: 100 jitter_ms: 50计算过程很直观第1次失败后等待100ms第2次失败后等待100ms * 2.0 200ms第3次失败后等待200ms * 2.0 400msjitter_ms: 50表示在每次等待时间上随机增加0-50ms的抖动避免大量请求在同一毫秒重试形成“重试风暴”。我们在线上环境把backoff_factor从2.0调到1.8因为实测发现某些数据库查询在200ms内恢复的概率高达89%没必要等到400ms。这个参数调整让平均任务完成时间缩短了1.2秒每天节省CPU时间约37小时。另一个关键配置是circuit_breaker熔断器circuit_breaker: failure_threshold: 5 success_threshold: 3 reset_timeout_ms: 60000熔断器有三种状态Closed关闭正常调用统计失败次数Open打开失败达到failure_threshold5次所有请求立即失败不发往CapabilityHalf-Open半开reset_timeout_ms60秒后允许1个请求试探若成功且连续success_threshold3次成功则回到Closed若失败回到Open。这个机制救了我们两次一次是MySQL主库切换期间从库延迟导致查询超时一次是第三方短信网关DNS解析失败。如果没有熔断Executor会持续重试把问题放大有了熔断它在60秒后自动恢复全程无需人工干预。最后是fallback_capability它不是“备用方案”而是“降级方案”。例如当mysql_query_executor熔断时我们配置fallback_capability: cache_query_executor后者从Redis缓存中返回上一次有效结果并附带source: cache字段。业务方看到这个字段就知道数据可能不是最新的但至少有结果可用——这比直接报错用户体验好得多。5. 常见问题与排查技巧实录那些文档里不会写的坑5.1 “Role服务返回500但Ollama日志显示模型在跑”——模型输出格式不匹配现象Executor日志里反复出现[task_idxxx] Role service returned 500, response: {error: Invalid JSON output}但手动curl Ollama API模型明明返回了正确JSON。排查思路先确认Executor发给Role的请求体。用tcpdump或mitmproxy抓包看实际POST的内容检查Role服务的output_schema是否和模型实际输出完全一致。常见陷阱模型输出{action_plan: {...}}但Schema要求{action_plan: {...}, metadata: {...}}少了一个字段模型输出timestamp: 2024-05-20T14:22:35Z但Schema要求format: date-time而Z结尾的ISO格式是合法的问题可能出在Ollama的JSON输出里多了不可见字符如BOM头模型在思考
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →