LangChain和MAF-04]针对消息的设计 System用于设定模型的人格、行为准则和专业领域定义AI是谁、该怎么说话、不能做什么。示例“你是一位资深的Python程序员请用幽默简洁的风格回答问题不要使用过多的技术术语。”它具有最高优先级能从宏观上约束模型的输出风格确保模型不会在长对话中出戏User代表真实用户提出的问题、指令或输入的信息。提供具体的任务请求比如“帮我写一段冒泡排序的代码”。这种类型的效用用于触发模型的响应机制是互动的核心驱动力Assistant代表AI模型之前生成的响应内容。它会记录对话历史维持上下文连贯性。在多轮对话中开发者会将模型之前的回答标记为assistant重新传给模型。这样模型才知道自己刚刚说过什么从而实现记忆功能Tool代表模型调用工具的输入和输出。它用于实现模型与外部工具如API、数据库、文件系统等的交互。通过将工具调用的输入输出封装成Tool消息模型能够理解何时需要调用工具以及如何处理工具返回的结果这种基于多角色对话机制用以解决如下的问题上下文管理通过区分谁说了什么模型能准确区分用户的要求和自己的回答避免产生逻辑混乱人设稳定性在角色扮演场景中系统角色可以持续强化角色的背景故事和性格提供沉浸感安全性与约束开发者可以在系统消息中设置安全边界防止模型产生违规内容少样本学习 (Few-shot)开发者常利用user和assistant通过示例对话来引导模型学习特定的任务格式或风格LangChain和MAF针对基于角色的消息设计了一个完整的消息体系但是它们的设计思路和实现方式却有所不同。LangChainLangChain的消息类型直接或者间接地继承自如下这个BaseMessage基类这是一个派生自Serializable的可序列化的类型。对于基类的BaseMessage来说表示消息内容的content字段可以是单纯的字符串或字典Key为字符串的列表其他于消息相关信息存储在additional_kwargs字段对应的字典中比如LLM返回的AIMessage可以利用它来保存涉及的工具调用。response_metadata字段用于存储响应的元数据比如响应的Header、LLM的名称涉及的Token消费数据等。class BaseMessage(Serializable):content: str | list[str | dict]additional_kwargs: dict Field(default_factorydict)response_metadata: dict Field(default_factorydict)type: strname: str | None Noneid: str | None Field(defaultNone, coerce_numbers_to_strTrue)property def content_blocks(self) - list[types.ContentBlock]class ChatMessage(BaseMessage):role: strtype: Literal[“chat”] “chat”消息承载的内容多种多样可以是简单的文本还可以是多媒体图片、音频和视频还可以是一个任意的二进制文件不同类型的内容具有不同的处理方式所以LangChain利用ConentBlock这个类型实现了内容的标准化。类似于HTTP的MIME类型每个ConentBlock对象都关联一个标准的类型名称很多采用的就是MIME类型。BaseMessage的content_blocks属性实现了原始形态的内容到ConentBlock列表的转换。我们可以指定绑定的角色创建一个ChatMessage作为Chat模型的消息也可以使用如下这些已经绑定好角色的消息类型。1.1 四种预设消息类型1.1.1 SystemMessage在LangChain以及底层的 Chat API 架构中系统消息是用于定义模型人格与运行规则的核心组件。它告诉 AI “你是谁”例如资深Python开发者、苏格拉底式的导师、或是一只可爱的猫娘。规定模型不能做什么例如严禁提及竞争对手、不准输出代码、只能用JSON格式回答。它通常位于消息列表的最顶端作为整个对话的宪法其权重通常高于普通的消息。class SystemMessage(BaseMessage):type: Literal[“system”] “system”1.1.2 HumanMessageHumanMessage代表了对话的需求侧即真实用户发送给模型的消息。它是用户意图的直接表达包含了模型需要完成的具体任务或提出的疑问。class HumanMessage(BaseMessage):type: Literal[“human”] “human”1.1.3 AIMessageAIMessage代表模型生成的响应。它是对话闭环的关键承载了AI的回答、推理逻辑及工具调用指令。它们是模型在接收到SystemMessage和HumanMessage后产生的输出。如果涉及针对工具的调用描述每个工具调用的ToolCall会出现在tool_calls字段返回的列表中另一个invalid_tool_calls字段返回于工具调用相关的错误。ToolCall是一个类型化字典定义了调用的工具名称、传入的参数和当前工具调用的唯一标识。class AIMessage(BaseMessage):tool_calls: list[ToolCall] Field(default_factorylist)invalid_tool_calls: list[InvalidToolCall] Field(default_factorylist)usage_metadata: UsageMetadata | None Nonetype: Literal[“ai”] “ai”property def content_blocks(self) - list[types.ContentBlock]class ToolCall(TypedDict):name: strargs: dict[str, Any]id: str | Nonetype: NotRequired[Literal[“tool_call”]]1.1.4 ToolMessageToolMessage属于对话的执行层用于向模型反馈外部工具执行的结果。当Agent接收到LLM发出的带有tool_calls的AIMessage后它会执行对应的工具并将结果包装在ToolMessage中反馈给LLM。它的tool_call_id和status字段分别标识工具调用的标识和状态前者用于关联AIMessage中的某个具体的ToolCall。class ToolMessage(BaseMessage, ToolOutputMixin):tool_call_id: strtype: Literal[“tool”] “tool”artifact: Any Nonestatus: Literal[“success”, “error”] “success”1.2 消息内容块BaseMessage的content_blocks字段承载消息主体内容它返回一个ContentBlock对象的列表。表示内容块的ContentBlock被定义成如下所示的Union类型,接下来我们看看具体的类型承载了什么样的内容ContentBlock (TextContentBlock| InvalidToolCall| ReasoningContentBlock| NonStandardContentBlock| DataContentBlock| ToolContentBlock)1.2.1 TextContentBlockTextContentBlock块是最常见的内容块类型它承载了文本内容以及与文本相关的元信息。它的text字段存储了文本内容annotations字段存储了文本的注释信息如加粗、斜体、链接等index字段用于表示文本在原始消息中的位置extras字段可以存储一些额外的信息比如文本的语言、情感倾向等。class TextContentBlock(TypedDict):type: Literal[“text”]id: NotRequired[str]text: strannotations: NotRequired[list[Annotation]]index: NotRequired[int | str]extras: NotRequired[dict[str, Any]]1.2.2 InvalidToolCall当LLM返回的AIMessage中包含工具调用时如果工具调用的格式不正确或者参数有误就会被记录在invalid_tool_calls字段中。InvalidToolCall类型化字典定义了无效工具调用的相关信息包括工具名称、传入的参数、错误信息以及当前工具调用的唯一标识等。class InvalidToolCall(TypedDict):type: Literal[“invalid_tool_call”]id: str | Nonename: str | Noneargs: str | Noneerror: str | Noneindex: NotRequired[int | str]extras: NotRequired[dict[str, Any]]1.2.3 ReasoningContentBlockReasoningContentBlock块用于承载LLM的推理过程中的一些中间结果或者推理步骤的描述信息。它的reasoning字段可以存储LLM在推理过程中生成的一些解释性文本或者推理步骤的描述index字段用于表示这个推理内容块在原始消息中的位置extras字段可以存储一些额外的信息比如推理的类型、相关的输入输出等。class ReasoningContentBlock(TypedDict):type: Literal[“reasoning”]id: NotRequired[str]reasoning: NotRequired[str]index: NotRequired[int | str]extras: NotRequired[dict[str, Any]]1.2.4 DataContentBlockDataContentBlock块用于承载一些非文本类型的内容比如图片、视频、音频或者文件等。它是一个Union类型可以表示不同类型的非文本内容块。可以是ImageContentBlock、VideoContentBlock、AudioContentBlock、PlainTextContentBlock或者FileContentBlock中的任意一种每种类型都对应着不同的内容格式和相关的元信息。DataContentBlock (ImageContentBlock| VideoContentBlock| AudioContentBlock| PlainTextContentBlock| FileContentBlock)1.2.5 ToolContentBlockToolContentBlock块用于承载与工具调用相关的内容。它是一个Union类型可以表示不同类型的工具内容块。可以是ToolCall、ToolCallChunk、ServerToolCall、ServerToolCallChunk或者ServerToolResult中的任意一种每种类型都对应着不同的工具调用格式和相关的元信息。ToolContentBlock (ToolCall | ToolCallChunk | ServerToolCall | ServerToolCallChunk | ServerToolResult)对于LangChain中的各种消息和内容块类型在我们的如下两篇文章中具有详细的介绍消息——Agent与模型交互的媒介多形态的消息内容——多模态AI解决方案的基础2. MAF消息在MAF通过如下这个ChatMessage类来表示。public class ChatMessage{public string? AuthorName{ get; set; }public DateTimeOffset? CreatedAt { get; set; }public ChatRole Role { get; set; }public string Text Contents.ConcatText();public IList Contents{ get; set; }public string? MessageId { get; set; }public object? RawRepresentation { get; set; }public AdditionalPropertiesDictionary? AdditionalProperties { get; set; }}ChatMessage的属性成员说明如下AuthorName消息发送者的名称可以是用户、模型或者工具等CreatedAt消息创建的时间戳Role消息发送者的角色通常是一个枚举类型如用户、模型、工具等Text消息的文本内容实际上是对Contents中所有内容的文本进行拼接后的结果Contents消息的内容列表每个内容都是一个AIContent对象AIContent是一个抽象类代表了消息内容的基类可以有不同类型的内容如文本、图片、文件等MessageId消息的唯一标识符可以用于消息的追踪和管理RawRepresentation消息的原始表示可以用于存储一些与消息相关的原始数据如模型返回的原始响应等AdditionalProperties一个字典用于存储一些额外的属性信息可以在Agent的运行过程中使用这些属性来进行一些自定义的逻辑处理出于可扩展的考虑Role并不是一个简单的枚举类型而是一个具有更丰富功能的结构体。它预定义了System、Assistant、User和Tool四个角色并且允许用户自定义角色。ChatMessage中的Role属性就是利用这个ChatRole结构体来表示消息发送者的角色。public readonly struct ChatRole : IEquatable{public static ChatRole System { get; } new ChatRole(“system”);public static ChatRole Assistant { get; } new ChatRole(“assistant”);public static ChatRole User { get; } new ChatRole(“user”);public static ChatRole Tool { get; } new ChatRole(“tool”);public string Value { get; }}2.1 AIContent在LangChain中消息内容被抽象成了ContentBlock而在MAF中与之对应的类型就是如下所示的AIContent。AIContent是MAF框架中定义一切交互内容的原子基类。它采用高度多态的设计将AI与用户之间的对话拆解为多种专业化的内容块。在传统的AI开发中消息通常只有Text。而AIContent将对话模型化为一个多模态、多状态的流。public class AIContent{public IList? Annotations { get; set; }[JsonIgnore]public object? RawRepresentation { get; set; }public AdditionalPropertiesDictionary? AdditionalProperties { get; set; }}AIContent的Annotations返回一个AIAnnotation的列表AIAnnotation是一个注解类用于为内容提供一些额外的信息或者标记。AIAnnotation也是一个多态类型通过JsonDerivedTypeAttribute声明了不同的子类型如CitationAnnotation等。[JsonPolymorphic(TypeDiscriminatorPropertyName “$type”)][JsonDerivedType(typeof(CitationAnnotation), typeDiscriminator: “citation”)]public class AIAnnotation{public IList? AnnotatedRegions { get; set; }[JsonIgnore]public object? RawRepresentation { get; set; }public AdditionalPropertiesDictionary? AdditionalProperties { get; set; }}public class CitationAnnotation : AIAnnotation{public string? Title { get; set; }public Uri? Url { get; set; }public string? FileId { get; set; }public string? ToolName { get; set; }public string? Snippet { get; set; }}CitationAnnotation是AIAnnotation的一个子类用于表示引用注解它具有如下的属性成员Title引用的标题可以是文章标题、网页标题等Url引用的URL地址可以是文章链接、网页链接等FileId引用的文件ID如果引用的是一个文件可以通过这个ID来获取文件的相关信息ToolName引用的工具名称如果引用的是一个工具可以通过这个名称来获取工具的相关信息Snippet引用的内容片段可以是引用内容的摘要、引用内容的一部分等AnnotatedRegion是AIAnnotation中的一个属性成员它代表了被注解的内容区域可以是文本区域、图像区域等。AnnotatedRegion同样是一个多态类型通过JsonDerivedTypeAttribute声明了不同的子类型如TextSpanAnnotatedRegion等。[JsonPolymorphic(TypeDiscriminatorPropertyName “$type”)][JsonDerivedType(typeof(TextSpanAnnotatedRegion), “textSpan”)]public class AnnotatedRegion{}public sealed class TextSpanAnnotatedRegion : AnnotatedRegion{[JsonPropertyName(“start”)]public int? StartIndex { get; set; }[JsonPropertyName(end)] public int? EndIndex { get; set; }}2.2 各种类型的AIContentMAF定义了多种类型的AIContent每种类型的AIContent都代表了不同的内容格式和相关的元信息。这些类型体现在标注在AIContent上的19个JsonDerivedTypeAttribute特性。[JsonPolymorphic(TypeDiscriminatorPropertyName “$type”)][JsonDerivedType(typeof(DataContent), typeDiscriminator: “data”)][JsonDerivedType(typeof(ErrorContent), typeDiscriminator: “error”)][JsonDerivedType(typeof(FunctionCallContent), typeDiscriminator: “functionCall”)][JsonDerivedType(typeof(FunctionResultContent), typeDiscriminator: “functionResult”)][JsonDerivedType(typeof(HostedFileContent), typeDiscriminator: “hostedFile”)][JsonDerivedType(typeof(HostedVectorStoreContent), typeDiscriminator: “hostedVectorStore”)][JsonDerivedType(typeof(TextContent), typeDiscriminator: “text”)][JsonDerivedType(typeof(TextReasoningContent), typeDiscriminator: “reasoning”)][JsonDerivedType(typeof(UriContent), typeDiscriminator: “uri”)][JsonDerivedType(typeof(UsageContent), typeDiscriminator: “usage”)][JsonDerivedType(typeof(ToolCallContent), typeDiscriminator: “toolCall”)][JsonDerivedType(typeof(ToolResultContent), typeDiscriminator: “toolResult”)][JsonDerivedType(typeof(InputRequestContent), typeDiscriminator: “inputRequest”)][JsonDerivedType(typeof(InputResponseContent), typeDiscriminator: “inputResponse”)][JsonDerivedType(typeof(ToolApprovalRequestContent), typeDiscriminator: “toolApprovalRequest”)][JsonDerivedType(typeof(ToolApprovalResponseContent), typeDiscriminator: “toolApprovalResponse”)][JsonDerivedType(typeof(McpServerToolCallContent), typeDiscriminator: “mcpServerToolCall”)][JsonDerivedType(typeof(McpServerToolResultContent), typeDiscriminator: “mcpServerToolResult”)]public class AIContent{}2.2.1 TextContentTextContent是AIContent的一个子类用于表示文本内容它对应着LangChain中TextContentBlock。它具有一个Text属性用于存储文本内容。public sealed class TextContent : AIContent{public string Text{get;set;}public TextContent(string? text);}2.2.2 TextReasoningContentTextReasoningContent用于表示推理内容它对应着LangChain中ReasoningContentBlock。它具有一个Text属性用于存储推理内容以及一个可选的ProtectedData属性用于存储一些需要保护的数据比如敏感信息、隐私数据等。public sealed class TextReasoningContent : AIContent{public string Text{get;set;}public string? ProtectedData { get; set; }public TextReasoningContent(string? text);}2.2.3 DataContentDataContent用于承载多媒体数据内容它对应着LangChain中DataContentBlock其属性定义如下public class DataContent : AIContent{public string Uri { get; }public string MediaType { get; }public string? Name { get; set; }public ReadOnlyMemory Data{ get; }public ReadOnlyMemory Base64Data{ get; }public DataContent(Uri uri, string? mediaType null);}属性说明如下Uri数据内容的URI地址可以是一个文件路径、一个网络链接等MediaType数据内容的媒体类型通常是一个MIME类型如image/png、application/pdf等,默认为application/octet-streamName数据内容的名称可以是文件名、图片名等Data数据内容的二进制数据以字节数组的形式存储Base64Data数据内容的Base64编码字符串以字符数组的形式存储2.2.4 ToolCallContentToolCallContent用于表示工具调用内容工具在MAF中通过基类AITool表示它具有一系列的子类,比较典型是AIFunction。派生于ToolCallContent的FunctionCallContent承载的正式针对AIFunction的工具调用我们可以认为它与LangChain的TollCall对标。public class ToolCallContent : AIContent{public string CallId { get; }public ToolCallContent(string callId);}public class FunctionCallContent : ToolCallContent{public string Name { get; }public IDictionarystring, object?? Arguments { get; set; }public Exception? Exception { get; set; }public bool InformationalOnly { get; set; }}属性说明如下CallId工具调用的唯一标识符用于关联工具调用的输入和输出Name函数调用的名称表示要调用的函数的名称Arguments函数调用的参数以字典的形式存储键为参数名称值为参数值Exception函数调用过程中发生的异常如果调用过程中出现了错误可以将异常信息存储在这个属性中InformationalOnly一个布尔值表示这个函数调用是否仅用于提供信息还是需要实际执行。如果为true表示这个函数调用只是为了提供一些信息给模型而不需要真正执行函数的逻辑虽然LangChain的工具由两种实现Tool和StructuredTool但是ToolCall并不区分这两种实现。MAF则不同基本上每个具体的AITool类型都具有各自的ToolCallContent类型CodeInterpreterToolCallContent用于表示代码解释器工具的调用内容包含了代码解释器工具调用的相关信息如要执行的代码、编程语言等ImageGenerationToolCallContent用于表示图像生成工具的调用内容包含了图像生成工具调用的相关信息如要生成的图像的描述、图像的尺寸等McpServerToolCallContent用于表示MCP服务器工具的调用内容包含了MCP服务器工具调用的相关信息如要调用的MCP服务器工具的名称、传入的参数等WebSearchToolCallContent用于表示网络搜索工具的调用内容包含了网络搜索工具调用的相关信息如要搜索的关键词、搜索引擎等2.2.5 ToolResultContentToolCallContent表示由LLM生成的针对指定工具的调用意图Agent根据此对象调用对应的工具并将执行结果封装成ToolResultContent对象反馈给LLM。继承自的ToolResultContent的FunctionResultContent类型对应的正是LangChain中ToolConentBlockToolConentBlock作为ToolMessage的主体内容。FunctionResultContent的Result和Exception属性分别用于存储工具调用的结果和调用过程中发生的异常信息如果工具调用成功Result属性将包含工具执行的结果如果工具调用失败Exception属性将包含相关的异常信息。public class ToolResultContent : AIContent{public string CallId { get; }public ToolResultContent(string callId);}public class FunctionResultContent : ToolResultContent{public object? Result { get; set; }public Exception? Exception { get; set; }}对于上面介绍的四个ToolCallContent类型FunctionCallContent、ImageGenerationToolCallContent、McpServerToolCallContent和WebSearchToolCallContent它们都有对应的ToolResultContent类型分别用于表示对应工具调用的结果内容如FunctionResultContent、ImageGenerationToolResultContent、McpServerToolResultContent和WebSearchToolResultContent等。2.2.6 其他除了上面介绍的这些AIContent类型之外MAF中还有一些其他类型的AIContentErrorContent用于表示错误内容HostedFileContent用于表示托管文件内容HostedVectorStoreContent用于表示托管向量存储内容UriContent用于表示URI内容UsageContent用于表示Token消费统计内容InputRequestContentLLM在执行过程中如果需要从用户那里获取一些输入信息可以通过InputRequestContent来向用户发出输入请求。ToolApprovalRequestContent是它的子类当LLM生成需要人工审批的工具调用时会反向请求用户进行审批此对象用于描述这样的审批请求;InputResponseContent针对InputRequestContent的响应内容用于表示用户提供的输入信息。ToolApprovalResponseContent是它的子类描述针对ToolApprovalRequestContent