第8章(2)——项目二:Claude与显示思考——引用资料
- 8.8 metadata显示思考的工具和资料
- 8.8.1 metadata显示思考——使用工具
- 8.8.2 项目二:Claude与显示思考——引用资料
8.8 metadata显示思考的工具和资料
gr.Chatbot组件支持参数metadata,因此可以原生支持显示中间思考过程,呈现使用工具和资料引用情况,这非常适合为LLM Agent和CoT(Chain-of-Thought, 思维链)演示创建UI。本节先通过一个简单示例展示如何呈现使用工具,然后通过一个项目展示如何使用gr.Chatbot构建显示思考中的资料引用。
8.8.1 metadata显示思考——使用工具
仔细的读者会发现,gr.ChatMessage类似于openai风格的消息格式,它有一个指向聊天消息内容的“content”键,但也包括一个“metadata”键,其值是字典gr.MetadataDict。如果字典包含“title”键,标题显示在思考过程之上,且生成的消息将呈现为中间思考过程。其用法如代码8-13所示:
importgradioasgrdefgenerate_response(message,history):history.append(gr.ChatMessage(role="user",content="input message: "+message))history.append(gr.ChatMessage(role="assistant",content="The weather API says it is 20 degrees Celcius in San Francisco.",metadata={"title":"🛠 Used tool Weather API","id":222,"parent_id":"111"}))return"",historywithgr.Blocks()asdemo:chatbot=gr.Chatbot(value=[{"role":"user","content":"What is the weather in San Francisco?"},{"role":"assistant","content":"I need to use the weather API tool","metadata":{"title":"🧠 Thinking","id":"111"}}])msg=gr.Textbox()msg.submit(generate_response,[msg,chatbot],[msg,chatbot])demo.launch()示例模拟代理使用天气API工具的思考过程。用户输入消息后,系统会生成两条记录:一条是用户的输入,另一条是助手调用工具后的回复。chatbot的初始值可理解为代理思考后的执行步骤,再次提交时开始调用天气API工具生成新回复;新回复消息根据"parent_id"附加到父类metadata消息中,并通过gr.Chatbot组件展示所有对话历史,运行界面如图8-10所示:
8.8.2 项目二:Claude与显示思考——引用资料
Gradio的聊天机器人可以显示来自大语言模型响应的引用(Citation),非常适合展示来源文档和参考资料。下面展示如何使用Anthropic Claude API构建支持引用功能的聊天机器人,它既能显示响应也能显示引用资料。
首先,设置ANTHROPIC_API_KEY并导入库,如代码8-14所示:
importgradioasgrimportanthropicimportbase64fromtypingimportList,Dict,Any DEFAULT_DOC="The grass is pink and soil is green. The sky is red while the sun is blue."然后,定义读取文件函数、存储用户输入消息函数、格式化历史消息函数、更新变量函数和机器人响应处理函数。这里只展示核心的机器人响应处理函数bot_response,其他函数请参考线上资源。代码如下所示:
defbot_response(history:list,enable_citations:bool,doc_type:str,text_content:str,pdf_file:str,api_key:str)->List[Dict[str,Any]]:try:ifnotapi_key:history.append({"role":"assistant","content":"Please provide your Anthropic API key to continue."})returnhistory client=Anthropic(api_key=api_key)messages=format_message_history(history,enable_citations,doc_type,text_content,pdf_fileifpdf_fileelseNone)response=client.messages.create(model="claude-sonnet-4-6",max_tokens=1024,messages=messages)main_response=""citations=[]# Process each content block, append to main response and citationsforblockinresponse.content:ifblock.type=="text":main_response+=block.textifenable_citationsandhasattr(block,'citations')andblock.citations:forcitationinblock.citations:ifcitation.cited_textnotincitations:citations.append(citation.cited_text)history.append({"role":"assistant","content":main_response})# Add citations if any were found and citations are enabledifenable_citationsandcitations:history.append({"role":"assistant","content":"\n".join([f"•{cite}"forciteincitations]),"metadata":{"title":"📚 Citations"}})returnhistory最后,创建Gradio界面:
withgr.Blocks(fill_height=True)asdemo:gr.Markdown("# Chat with Anthropic Claude's Citations")withgr.Row(scale=1):withgr.Column(scale=4):chatbot=gr.Chatbot(show_label=False,scale=1)msg=gr.Textbox(placeholder="Enter your message here...",show_label=False,container=False)withgr.Column(scale=1):api_key=gr.Textbox(type="password",label="Anthropic API Key",placeholder="Enter your API key",interactive=True,info="Your API key will not be stored")enable_citations=gr.Checkbox(label="Enable Citations",value=True,info="Toggle citation functionality")doc_type_radio=gr.Radio(choices=["plain_text","pdf","combined"],value="plain_text",label="Document Type",info="Choose the type of document(s) to reference")text_input=gr.Textbox(label="Document Content",placeholder=f"Enter your document text here.\nDefault text will be picked if citations are enabled and you don't provide the documents. Default document is --{DEFAULT_DOC}",lines=10,info="Enter the text you want to reference")pdf_input=gr.File(label="Upload PDF",file_count="multiple",file_types=[".pdf"],type="filepath",visible=False)clear=gr.ClearButton([msg,chatbot,text_input,pdf_input])# Update input visibility based on settingsenable_citations.change(update_document_inputs,inputs=[enable_citations,doc_type_radio],outputs=[doc_type_radio,text_input,pdf_input])doc_type_radio.change(update_document_inputs,inputs=[enable_citations,doc_type_radio],outputs=[doc_type_radio,text_input,pdf_input])# Handle message submissionmsg.submit(user_message,[msg,chatbot,enable_citations,doc_type_radio,text_input,pdf_input,api_key],[msg,chatbot],queue=False).then(bot_response,[chatbot,enable_citations,doc_type_radio,text_input,pdf_input,api_key],chatbot)if__name__=="__main__":demo.launch(theme="ocean",debug=True)本例实现了一个基于Anthropic Claude API的交互式聊天机器人界面,并可选择性地提供文本、多个PDF文档或二者混合作为上下文,同时支持模型生成内容的引用溯源。其核心功能主要有函数bot_response及构建GUI,下面分别讲述。
首先,看一下核心函数bot_response。它实现了一个基于Anthropic Claude模型的交互式聊天机器人,发送消息并提取回复内容和引用信息:
(1)API认证与响应:调用format_message_history函数,将历史消息、引用文本或PDF文档转化为Claude模型能接受的格式;通过用户提供的API密钥初始化Anthropic客户端,然后调用指定模型Claude Sonnet 4生成响应。
(2)解析响应内容:分离主回复和引用信息,当enable_citations选项开启并且回复中有属性’citations’时,将首次出现的引用信息添加到引用列表。
(3)返回聊天历史:将主回复和可能的引用列表追加到聊天历史,通过键metadata将更新后的聊天历史用作界面显示,此外还支持引用功能的启用/禁用控制。
然后,使用Gradio库构建一个功能完整的图形用户界面(GUI)。用于与Anthropic Claude模型进行交互,并支持文档引用功能。以下是详细解析:
(1)界面布局与核心组件:使用gr.Blocks创建界面,设置fill_height=True使界面占满浏览器高度,同时设置标题。然后创建多个核心组件,例如gr.Chatbot、gr.Checkbox、gr.Radio、gr.File及gr.ClearButton等。
(2)交互逻辑:①调整组件的可见性。enable_citations.change和doc_type_radio.change事件监听器调用update_document_inputs函数,该函数根据用户是否启用引用以及选择的文档类型(纯文本、PDF或组合),动态控制界面上文本输入框和PDF上传组件的显示与隐藏。②消息处理流程。首先当用户在消息输入框按下回车时,调用user_message函数,将用户输入的消息添加到聊天历史中,并清空输入框;然后通过then()链式调用bot_response函数,将完整的聊天历史(包括新用户消息)、引用设置、文本及文档内容、API密钥传递给它,以生成机器人的回复,并更新聊天机器人组件显示的内容。
(3)应用启动:if判断确保当脚本直接运行时,会启动Gradio应用,采用"ocean"主题并开启调试模式(debug=True)。
在安装包anthropic后启动,执行以下操作:①在页面输入ANTHROPIC_API_KEY,不过为安全起见,建议在本地运行程序并设置;②在选择引用文档类型时,选择“combined”,上传总数不超过100页的PDF文档。也可上传其它格式文档,只要编码为utf-8即可;③输入文档内容和要求,比如要求总结论文内容,输入“Please provide a brief summary of the papers.”,回车后运行界面如图8-11所示:
引用功能与Gradio聊天机器人的元数据功能metadata配合得特别好,通过创建可折叠部分,既保持聊天界面的简洁,又能轻松访问来源文档,从而创建更透明和可信的交互体验。Hugging Face线上完整代码请参阅:ysharma/anthropic-citations-with-gradio-metadata-key🖇️链接8-5。经过版本更迭后可能出现运行错误,读者可参考本书线上修正后的代码。