在实际的古钱币鉴定场景中单靠一张图片让大模型直接下结论结果往往不可靠。真正可用的做法是把“观察、推理、查证、输出报告”拆成多个步骤让一个 Agent 来编排流程再让不同的大模型分别承担识别和判断工作。这篇文章记录的是一个可行的演示项目使用 Claude Agent 负责任务拆解与工具调用使用智谱 GLM 大模型的多模态能力完成钱币图像识别最终输出一份结构化的鉴定结果。适合阅读这篇文章的读者有两类一类是做 AI 应用开发想了解 Agent 如何编排多模态识别任务另一类是收藏、文博或电商场景的技术人员想把 AI 钱币鉴定从“能跑通”推进到“基本可用”。读完以后你会得到一套最小可运行的代码框架也能知道图片输入、模型参数、错误排查和报告输出这些环节分别要如何处理。需要先说明一点不同时间开放的模型版本和接口风格可能不同文中使用的模型名、请求地址和参数是演示值。落地时要以你实际开通的账号和官方文档为准不要照抄版本号。1. 先搞清楚AI 钱币鉴定为什么要用“Agent 大模型”而不是单模型1.1 古钱币鉴定的识别难点从哪来古钱币鉴定不是简单“看图说话”。一枚钱币出现在镜头前至少包含几层信息第一层是图面信息。钱币的材质、锈色、包浆、穿口形状、外廓宽窄、文字书写风格都会影响判断。不同品相的同一枚钱币在照片上的表现差异很大。第二层是文字信息。很多古钱币正面和背面都有钱文比如“乾隆通宝”“光绪元宝”但字口可能模糊、磨损或者被锈覆盖。OCR 模型直接识别经常出错因为钱文是铸造体不是现代印刷体。第三层是背景知识。判断一枚钱币是哪个朝代、哪个局铸造需要把文字、形制和时代特征连起来判断。比如同样是“通宝”宋代的形制和清代就有明显差别。如果只把一个视觉大模型的输出当作最终结论很容易出现两个问题模型只描述了“图里有什么”却不告诉你“为什么这样判断”或者模型给出了一个很自信的结论但其实没有经过任何查证。所以这类任务更适合用一个 Agent 做编排先观察图片再做知识查证最后把结论和依据一起输出。1.2 Claude Agent 和智谱 GLM 在流程里分别承担什么角色在这个项目中两个模型的分工非常明确。Claude Agent 是“调度者”。它负责理解用户的鉴定目标拆解成多个子任务决定先调用哪个工具、什么时候需要再观察一次图片、最后如何汇总报告。它的工作方式不是一次性生成答案而是通过工具调用机制一个回合一个回合地推进。智谱 GLM 大模型是“识别者”。这里主要用到它的多模态能力输入图片和提示词输出钱币特征识别结果包括钱文、面值、形制、品相、可能的朝代范围等。为什么不让一个模型把两件事都做完原因有三点任务隔离更清晰。调度和识别混在一个提示词里模型容易顾此失彼。拆分后每一段提示词的目标都更单一。更容易替换模型。如果后续觉得 GLM 识别效果不好可以换成其他多模态模型Agent 侧的代码不用大改。方便人工介入。识别结果和最终报告分开存储鉴定师可以只审核识别结果再决定是否采纳。1.3 为什么不是只调用一个视觉模型直接调用单个视觉模型也不是不能做但把它放到真实场景里看会暴露很多问题。对比项只用单一视觉模型Agent 大模型方案识别过程输入图片直接输出结论先观察再查证后报告结论可解释性低模型只说结果高报告里能带识别依据复杂图片处理一次失败就要换提示词重试Agent 可以调整工具参数或重新观察知识查证能力依赖模型内部记忆可接入本地知识库或参考表系统扩展性改场景要重写提示词新增工具和规则即可从表里能看出Agent 方案不是为了制造复杂度而是为了让整个鉴定链路具备“可暂停、可检查、可修正”的能力。这在涉及交易、收藏、拍卖等场景时尤其重要因为错误结论可能导致后续决策偏差。需要注意Agent 方案并不是魔法。如果没有好的工具函数、清晰的提示词和可靠的识别模型Agent 也会在错误的路线上走下去。后面几节会逐步把这套链路搭起来。2. 环境准备和依赖对齐这一步决定后面能不能跑通2.1 准备 API 凭证和环境变量这个项目至少需要两组凭证一组是 Claude API 的另一组是智谱开放平台的。不同平台的凭证获取方式不一样但流程类似注册账号、开通模型服务、创建 API Key、在控制台确认模型名称和计费方式。不要在生产环境把密钥直接写进代码。建议统一放在环境变量里本地开发时可以使用.env文件但要把.env加入.gitignore。export ANTHROPIC_API_KEY你的_claude_api_key export ZHIPU_API_KEY你的_智谱_api_key export CLAUDE_MODELclaude-sonnet-4-20250514 export ZHIPU_MODELglm-5.1注意模型版本号请以你账号下实际可用的模型名为准。如果开通的模型不叫这个后面的请求会直接报模型不存在。如果使用智谱的 OpenAI 兼容接口还需要确认接口地址。常见地址格式类似https://open.bigmodel.cn/api/paas/v4/但不同阶段的入口可能有差异最好在官方文档里确认后再填。2.2 Python 依赖和项目结构这个演示项目使用 Python主要依赖是anthropic和openai两个客户端库。anthropic用于调用 Claude APIopenai用于通过兼容模式调用智谱多模态接口。pip install anthropic openai python-dotenv pillowpython-dotenv用于读取.env文件Pillow用于图片的尺寸检查和压缩。目录结构可以这样组织coin-identify-agent/ ├── .env ├── app.py ├── agent/ │ ├── orchestrator.py │ └── prompts.py ├── models/ │ ├── glm_client.py │ └── claude_client.py ├── tools/ │ └── coin_tools.py ├── samples/ │ └── demo_coin.jpg └── output/ └── report.json这个结构把“Agent 编排”“模型调用”“工具函数”分开避免把所有逻辑塞进一个文件。2.3 图片输入目录与规范图片质量直接决定识别效果。在准备样本图片时建议按以下规范整理检查项推荐值说明图片格式JPG、PNG避免使用过大的 BMP 原图单边尺寸不小于 512 像素过小会丢失钱文细节文件大小建议压缩到 2MB 以内过大时 base64 编码后请求体可能超限背景纯色或浅色背景降低背景干扰拍摄角度尽量正视俯拍角度识别效果最好命名不包含中文和空格避免文件路径解析异常在代码里还可以在读取图片时先做一次强制转换确保输入给模型的图片尺寸不会太大。from PIL import Image def prepare_image(path: str, max_side: int 1024) - str: img Image.open(path) img.thumbnail((max_side, max_side)) tmp_path path .tmp.jpg img.convert(RGB).save(tmp_path, JPEG, quality85) return tmp_path这段代码会把图片最长边压缩到 1024 像素并转成 JPEG既保留了钱币主要细节又控制了传输体积。如果原图是透明的 PNG转成 RGB 还可以避免后续编码问题。3. 系统流程设计从一张钱币图片到结构化鉴定报告3.1 一条清晰的主流程AI 钱币鉴定的主流程可以概括为六步Agent 接收用户输入包括图片路径和鉴定意图。Agent 判断当前任务需要观察图片于是调用视觉识别工具。视觉识别工具把图片编码成 base64连同提示词一起发送给智谱 GLM 多模态接口。GLM 返回识别结果包含钱文、面值、形制、品相、可能年代等信息。Agent 根据识别结果决定是否需要查证本地参考数据或者直接生成最终报告。Agent 输出结构化 Markdown 或 JSON 报告并保留原始识别结果备查。这个流程不是写死的。Claude Agent 会根据识别结果做分支判断。比如如果第一次识别时钱文缺失Agent 可以要求工具重新裁剪图片局部再识别一次如果识别出多个候选年代Agent 可以并行查证两个候选信息再在报告里说明不确定性。3.2 Agent 的任务拆分为了让 Agent 能够在不写死脚本的情况下自动决策需要给它预留几个工具函数工具名输入输出用途analyze_coin_image图片路径、提示词识别结果 JSON调用 GLM 多模态识别search_coin_reference关键词、候选范围参考条目从本地知识库查证generate_report识别结果、参考条目报告文本组装最终鉴定报告save_report报告文本、输出路径文件状态持久化报告Agent 每回合只会调用一个或一组工具然后把工具返回结果作为新上下文继续推理。整个过程就是“观察—思考—行动—再观察”的循环。3.3 模型参数与每次调用的含义在调用大模型时参数不是随便填的。不同参数影响的是模型行为而不是单纯的“生成速度”。参数演示值含义与作用temperature0.1控制随机性鉴定场景推荐较低值max_tokens1500单次输出上限防止报告截断top_p0.9采样范围与 temperature 配合使用image_urldata URL图片以 data URL 形式传给视觉模型model环境变量控制关键时切换模型版本不写死在代码里鉴定类任务建议把 temperature 调低到 0.1 左右。如果调高到 0.7 以上同样的图片可能每次输出都不一样这对需要稳定结果的场景是不利的。不要把temperature0当作“一定稳定”。部分模型在 API 层仍然会做采样遇到复杂图片仍可能给出差异描述。为了稳定更重要的是把提示词写得具体并要求模型输出结构化字段。4. 核心代码实现最小可运行的鉴定链路4.1 Claude Agent 工具注册与循环这里先实现一个最简的 Agent 循环重点是展示 Claude 如何通过工具调用完成任务。import os import json from anthropic import Anthropic client Anthropic(api_keyos.environ[ANTHROPIC_API_KEY]) TOOLS [ { name: analyze_coin_image, description: 分析钱币图片返回钱文、形制、品相等结构化识别结果, input_schema: { type: object, properties: { image_path: {type: string, description: 钱币图片本地路径}, prompt: {type: string, description: 本次识别的重点关注内容} }, required: [image_path, prompt] } }, { name: save_report, description: 把最终鉴定报告保存到指定路径, input_schema: { type: object, properties: { content: {type: string, description: 报告内容}, output_path: {type: string, description: 保存路径} }, required: [content, output_path] } } ] def run_agent(user_request: str, image_path: str, output_path: str) - str: messages [ { role: user, content: [ { type: text, text: f用户请求{user_request}\n图片路径{image_path}\n输出路径{output_path} } ] } ] for _ in range(6): response client.messages.create( modelos.environ[CLAUDE_MODEL], max_tokens2000, toolsTOOLS, messagesmessages ) stop_reason response.stop_reason if stop_reason tool_use: tool_results [] for block in response.content: if block.type tool_use: tool_name block.name tool_input block.input if tool_name analyze_coin_image: result analyze_coin_image( image_pathtool_input[image_path], prompttool_input[prompt] ) elif tool_name save_report: result save_report( contenttool_input[content], output_pathtool_input[output_path] ) else: result json.dumps({error: unknown tool}) tool_results.append( { type: tool_result, tool_use_id: block.id, content: json.dumps(result, ensure_asciiFalse) } ) messages.append({role: user, content: tool_results}) else: return .join( block.text for block in response.content if block.type text ) return Agent reached max steps.这里的循环最多执行 6 轮避免 Agent 陷入无限工具调用。stop_reason是判断本轮是否触发工具调用的关键。如果返回tool_use就把工具执行结果拼到消息里继续追问否则说明 Agent 认为可以输出最终文本了。4.2 调用智谱 GLM 的多模态识别函数analyze_coin_image是整个链路里最关键的函数。它负责把图片编码成 data URL然后调用智谱多模态接口。import base64 import os import json from openai import OpenAI glm_client OpenAI( api_keyos.environ[ZHIPU_API_KEY], base_urlos.environ.get(ZHIPU_BASE_URL, https://open.bigmodel.cn/api/paas/v4/) ) def encode_image_to_data_url(image_path: str) - str: with open(image_path, rb) as f: encoded base64.b64encode(f.read()).decode(utf-8) return fdata:image/jpeg;base64,{encoded} def analyze_coin_image(image_path: str, prompt: str) - dict: data_url encode_image_to_data_url(image_path) response glm_client.chat.completions.create( modelos.environ[ZHIPU_MODEL], temperature0.1, messages[ { role: user, content: [ { type: image_url, image_url: { url: data_url } }, { type: text, text: prompt } ] } ] ) content response.choices[0].message.content return parse_model_output(content)parse_model_output负责把模型的文本输出转换成结构化 JSON。这里有两种策略如果模型已经按 JSON 格式返回就解析 JSON如果模型返回了 Markdown就做一次清洗再解析。演示项目里先按 JSON 解析并在提示词里明确要求。import re def parse_model_output(content: str) - dict: content content.strip() content re.sub(r^json\s*|\s*$, , content) try: return json.loads(content) except json.JSONDecodeError: return {raw_output: content, warning: 模型输出不是标准 JSON需要人工复核}这个容错很重要。实测中视觉模型虽然提示了 JSON 格式但偶尔仍会输出额外的解释文字解析失败时宁可保留原文也不要直接丢弃方便排查。4.3 鉴定结果组装与报告输出save_report函数负责落盘。为了避免覆盖历史数据推荐按时间戳生成文件。import datetime def save_report(content: str, output_path: str) - dict: ts datetime.datetime.now().strftime(%Y%m%d_%H%M%S) final_path output_path.replace(.json, f_{ts}.json) with open(final_path, w, encodingutf-8) as f: f.write(content) return {status: ok, path: final_path, size: len(content)}确保 output 目录存在否则写入会报错。import os def ensure_output_dir(path: str): directory os.path.dirname(path) if directory and not os.path.exists(directory): os.makedirs(directory, exist_okTrue)在app.py中把整个流程串起来from agent.orchestrator import run_agent if __name__ __main__: result run_agent( user_request请鉴定这枚钱币的朝代、钱文和品相并输出判断依据, image_pathsamples/demo_coin.jpg, output_pathoutput/report.json ) print(result)5. 运行验证预期输出和判定标准5.1 运行命令环境准备完成后在项目根目录执行python app.py如果正常控制台会打印一段鉴定报告文本同时在output/目录下生成带时间戳的 JSON 文件。5.2 输入图片样例和期望输出假设输入图片是一枚清晰的正反面合图钱文可辨认。GLM 多模态识别返回的 JSON 可能是这样{ coin_name: 乾隆通宝, dynasty: 清, reign_period: 乾隆, currency_system: 制钱, obverse_script: 乾隆通宝, reverse_script: 宝泉, possible_mint: 宝泉局, condition: { wear_level: 中, patina: 有明显包浆, defects: [边缘轻微磕碰] }, confidence: { coin_name: 0.92, mint: 0.71 }, analysis_basis: 钱文清晰形制符合清代乾隆时期制钱特征背面满文疑似宝泉局 }Agent 拿到这个结果后会把它整理成一份报告大致结构如下## 鉴定结果 - 钱名乾隆通宝 - 朝代清 - 推测铸局宝泉局 - 品相中边缘轻微磕碰 ## 判断依据 1. 正面钱文为“乾隆通宝”字口相对清晰。 2. 背面满文与宝泉局特征相近。 3. 包浆覆盖均匀符合传世品特征。 ## 不确定性 铸局识别置信度偏低满文局部略模糊建议人工复核背面高清图。5.3 验证步骤清单运行完成后不要只看“有没有输出”还要按清单检查是否生成了output/report_xxx.json文件。JSON 中是否包含coin_name、dynasty、condition等关键字段。是否有confidence字段用于表达不确定度。模型是否在输出里说明判断依据而不是只给结论。多次运行同一张图结论是否基本一致。改变图片后报告里是否出现了对应变化的描述而不是重复上一张图的结论。如果第六项失败基本可以确定是提示词或参数设计有问题让模型没有真正“看见”新图片。6. 常见问题排查从报错倒推原因6.1 高频报错与处理方案以下表格按“现象、原因、检查方式、解决建议”维护问题现象常见原因检查方式解决建议API 返回 401API Key 无效或已过期检查环境变量是否加载成功控制台重新生成密钥确认.env已引入或者直接 export 后重启进程模型不存在模型名写错或账号未开通该模型在智谱控制台查看可开通模型名称把环境变量改成实际模型名不要沿用演示值图片过大导致请求超时base64 编码后体积超过接口限制查看请求时间检查图片原始大小调用prepare_image压缩再编码多模态接口报“image_url 格式不支持”传入的是本地路径而不是 data URL打印 data_url 前 50 个字符先转 data URL再放入消息内容模型输出不是 JSON提示词约束不够强或模型生成被截断查看原始输出内容增加 JSON 格式示例调大 max_tokensAgent 陷入循环工具执行结果没有正确回传打印stop_reason和消息轮次检查tool_use_id是否正确匹配输出文件找不到output 目录不存在或路径写错检查os.path.dirname(output_path)是否为空启动时调用ensure_output_dir6.2 典型排查路径如果发现整条链路跑不同建议按顺序排查而不是先改提示词。第一步确认输入图片本身可读。直接用工具打开图片确认它不是空文件也不是损坏文件。第二步确认环境变量全部加载。在代码入口打印一段脱敏后的配置摘要比如是否有 api_key但不要打印完整密钥。第三步单独测试 GLM 识别函数。写一个临时脚本直接调用analyze_coin_image不经过 Agent看能否返回识别 JSON。from tools.coin_tools import analyze_coin_image result analyze_coin_image( image_pathsamples/demo_coin.jpg, prompt输出钱文、朝代、品相用 JSON 格式 ) print(result)这一步可以把问题快速分流如果单独调用失败说明问题在模型接口、图片或提示词如果单独调用成功说明问题在 Agent 编排层。第四步检查 Agent 消息轮次。把每一次 API 调用的stop_reason和执行工具名打印出来看有没有一直停留在同一个工具上。print(fstep{step}, stop_reason{stop_reason}, tool{tool_name})第五步检查报告文件。重点看confidence和analysis_basis如果置信度字段缺失说明提示词没有强调“必须输出不确定度”这时候补一句“如果没有把握在 confidence 中降低分数并说明原因”即可。排错时不要同时修改多个变量。一次只改一个参数或一段提示词跑通后再改下一个否则你很难知道是哪一步修复了问题。7. 最佳实践从 demo 走向可用的钱币鉴定工具7.1 数据、提示词与评估集演示项目能跑通和“能投入使用”之间还差一套评估机制。第一建立小规模评估集。准备 50 到 100 张已经由人工鉴定过的钱币图片记录每张图的正确朝代、钱文、铸局和品相作为 ground truth。每次改动提示词或模型参数后用同一套评估集跑一遍统计准确率变化。第二提示词要固定模板不要临时发挥。Agent 传给 GLM 的识别提示词应当包含识别目标、必须输出的字段、不确定时的处理方式、输出格式示例。示例提示词如下你是一名古钱币识别助手。请观察用户提供的钱币图片依次输出以下字段 1. coin_name钱文名称如“乾隆通宝” 2. dynasty可能的朝代 3. mint推测铸局如果不确定输出 null 4. condition品相描述 5. confidence你对每个字段的置信度数值范围 0 到 1 6. analysis_basis给出判断依据不超过 3 条。 如果图片不清晰或无法判断请直接在对应字段输出 null不要编造。第三保留每一张图的识别中间结果。不只保留最终报告还要保留 GLM 返回的原始 JSON、Agent 调用过哪些工具、每轮耗时。这样做的好处是当报告出问题时可以回溯是哪一层出的错。7.2 生产环境额外考虑从演示项目进入生产环境至少还要补齐下面几块API Key 管理。用密钥管理服务或环境变量注入不要写进镜像和代码仓库。日志与监控。每次鉴定请求都应该有日志记录图片 ID、模型版本、输入参数、识别结果、耗时和错误信息。限流与重试。两套模型 API 都有速率限制需要增加指数退避重试策略避免短时间大量请求触发限流。人工复核机制。对confidence低于阈值的鉴定结果强制进入人工复核队列。数据合规。使用的图片应来自合法渠道如有版权要求要在采集和使用前确认授权。模型版本固定。不要在日常运行中“顺手”切换模型版本每一次模型变更都要重新跑一遍评估集。考虑项学习方法示例生产要求示例API Key.env 文件密钥管理服务权限最小化日志print 输出结构化日志可检索错误处理直接抛异常重试队列 告警人工复核无置信度低时强制人工介入版本管理手写模型名记录每次请求使用的模型版本7.3 后续扩展方向这个架构搭好以后扩展空间比较大。可以把search_coin_reference工具从本地 JSON 扩展成真正的知识库检索接入钱币图谱或开放文献数据让 Agent 在识别前先查证钱文与铸局对应关系。可以增加局部识别能力。对一张正反面合图先做目标检测把正面和背面分别切出来再分别识别。这样比整图输入更容易获得准确的钱文结果。可以把报告输出成 PDF 或结构化表单方便交易平台和鉴定机构对接。也可以把 Claude Agent 替换成其他支持工具调用的模型对比不同调度模型的稳定性。7.4 风险与合规边界最后说一条容易被忽视的边界AI 鉴定的结果应始终作为“辅助判断”而不应直接等同于“权威鉴定证书”。在收藏和交易场景里错误鉴定可能引发纠纷。因此报告里要明确标注“AI 辅助鉴定结果仅供参考不构成最终鉴定意见”。同时不要使用来源不明的钱币图片作为训练数据也不要批量抓取商业平台的鉴定图片来做模型优化。数据合规和隐私保护在文博、电商场景里不是可有可无的选项而是一项必须提前设计的工程要求。对这个演示项目来说最值得继续做的不是“让模型更聪明”而是“让流程更可信”。把每张图的判断依据、置信度和人工复核记录都留下来这套工具才能真正在钱币鉴定场景里发挥价值。