Agent+多模态大模型:构建AI古钱币鉴定系统
2026/9/8 5:37:39 网站建设 项目流程

在实际的古钱币鉴定场景中,单靠一张图片让大模型直接下结论,结果往往不可靠。真正可用的做法是把“观察、推理、查证、输出报告”拆成多个步骤,让一个 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_MODEL="claude-sonnet-4-20250514" export ZHIPU_MODEL="glm-5.1"

注意:模型版本号请以你账号下实际可用的模型名为准。如果开通的模型不叫这个,后面的请求会直接报模型不存在。

如果使用智谱的 OpenAI 兼容接口,还需要确认接口地址。常见地址格式类似https://open.bigmodel.cn/api/paas/v4/,但不同阶段的入口可能有差异,最好在官方文档里确认后再填。

2.2 Python 依赖和项目结构

这个演示项目使用 Python,主要依赖是anthropicopenai两个客户端库。anthropic用于调用 Claude API,openai用于通过兼容模式调用智谱多模态接口。

pip install anthropic openai python-dotenv pillow

python-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", quality=85) return tmp_path

这段代码会把图片最长边压缩到 1024 像素,并转成 JPEG,既保留了钱币主要细节,又控制了传输体积。如果原图是透明的 PNG,转成 RGB 还可以避免后续编码问题。

3. 系统流程设计:从一张钱币图片到结构化鉴定报告

3.1 一条清晰的主流程

AI 钱币鉴定的主流程可以概括为六步:

  1. Agent 接收用户输入,包括图片路径和鉴定意图。
  2. Agent 判断当前任务需要观察图片,于是调用视觉识别工具。
  3. 视觉识别工具把图片编码成 base64,连同提示词一起发送给智谱 GLM 多模态接口。
  4. GLM 返回识别结果,包含钱文、面值、形制、品相、可能年代等信息。
  5. Agent 根据识别结果,决定是否需要查证本地参考数据,或者直接生成最终报告。
  6. 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 以上,同样的图片可能每次输出都不一样,这对需要稳定结果的场景是不利的。

不要把temperature=0当作“一定稳定”。部分模型在 API 层仍然会做采样,遇到复杂图片仍可能给出差异描述。为了稳定,更重要的是把提示词写得具体,并要求模型输出结构化字段。

4. 核心代码实现:最小可运行的鉴定链路

4.1 Claude Agent 工具注册与循环

这里先实现一个最简的 Agent 循环,重点是展示 Claude 如何通过工具调用完成任务。

import os import json from anthropic import Anthropic client = Anthropic(api_key=os.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( model=os.environ["CLAUDE_MODEL"], max_tokens=2000, tools=TOOLS, messages=messages ) 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_path=tool_input["image_path"], prompt=tool_input["prompt"] ) elif tool_name == "save_report": result = save_report( content=tool_input["content"], output_path=tool_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_ascii=False) } ) 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_key=os.environ["ZHIPU_API_KEY"], base_url=os.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 f"data: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( model=os.environ["ZHIPU_MODEL"], temperature=0.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", encoding="utf-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_ok=True)

app.py中把整个流程串起来:

from agent.orchestrator import run_agent if __name__ == "__main__": result = run_agent( user_request="请鉴定这枚钱币的朝代、钱文和品相,并输出判断依据", image_path="samples/demo_coin.jpg", output_path="output/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_namedynastycondition等关键字段。
  • 是否有confidence字段,用于表达不确定度。
  • 模型是否在输出里说明判断依据,而不是只给结论。
  • 多次运行同一张图,结论是否基本一致。
  • 改变图片后,报告里是否出现了对应变化的描述,而不是重复上一张图的结论。

如果第六项失败,基本可以确定是提示词或参数设计有问题,让模型没有真正“看见”新图片。

6. 常见问题排查:从报错倒推原因

6.1 高频报错与处理方案

以下表格按“现象、原因、检查方式、解决建议”维护:

问题现象常见原因检查方式解决建议
API 返回 401API Key 无效或已过期检查环境变量是否加载成功,控制台重新生成密钥确认.env已引入,或者直接 export 后重启进程
模型不存在模型名写错,或账号未开通该模型在智谱控制台查看可开通模型名称把环境变量改成实际模型名,不要沿用演示值
图片过大导致请求超时base64 编码后体积超过接口限制查看请求时间,检查图片原始大小调用prepare_image压缩,再编码
多模态接口报“image_url 格式不支持”传入的是本地路径,而不是 data URL打印 data_url 前 50 个字符先转 data URL,再放入消息内容
模型输出不是 JSON提示词约束不够强,或模型生成被截断查看原始输出内容增加 JSON 格式示例,调大 max_tokens
Agent 陷入循环工具执行结果没有正确回传打印stop_reason和消息轮次检查tool_use_id是否正确匹配
输出文件找不到output 目录不存在,或路径写错检查os.path.dirname(output_path)是否为空启动时调用ensure_output_dir

6.2 典型排查路径

如果发现整条链路跑不同,建议按顺序排查,而不是先改提示词。

第一步,确认输入图片本身可读。直接用工具打开图片,确认它不是空文件,也不是损坏文件。

第二步,确认环境变量全部加载。在代码入口打印一段脱敏后的配置摘要,比如是否有 api_key,但不要打印完整密钥。

第三步,单独测试 GLM 识别函数。写一个临时脚本,直接调用analyze_coin_image,不经过 Agent,看能否返回识别 JSON。

from tools.coin_tools import analyze_coin_image result = analyze_coin_image( image_path="samples/demo_coin.jpg", prompt="输出钱文、朝代、品相,用 JSON 格式" ) print(result)

这一步可以把问题快速分流:如果单独调用失败,说明问题在模型接口、图片或提示词;如果单独调用成功,说明问题在 Agent 编排层。

第四步,检查 Agent 消息轮次。把每一次 API 调用的stop_reason和执行工具名打印出来,看有没有一直停留在同一个工具上。

print(f"step={step}, stop_reason={stop_reason}, tool={tool_name}")

第五步,检查报告文件。重点看confidenceanalysis_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 辅助鉴定结果,仅供参考,不构成最终鉴定意见”。

同时,不要使用来源不明的钱币图片作为训练数据,也不要批量抓取商业平台的鉴定图片来做模型优化。数据合规和隐私保护在文博、电商场景里不是可有可无的选项,而是一项必须提前设计的工程要求。

对这个演示项目来说,最值得继续做的不是“让模型更聪明”,而是“让流程更可信”。把每张图的判断依据、置信度和人工复核记录都留下来,这套工具才能真正在钱币鉴定场景里发挥价值。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询