MAF(Microsoft Agent Framework)建立在MEAI(Microsoft.Extensions.AI)这个AI基础框架之上。MEAI是更加基础和通用的基础框架,以LLM/IChatClient为核心,MAF建立在MEAI之上,并在此基础上构建Agent。MEAI自身也需要一套评估系统用来评估LLM/IChatClient的产出。MeaiEvaluatorAdapter在这两个评估系统之间提供了适配。
1. IEvaluator
MEAI的评估系统以IEvaluator这个接口为核心。作为MEAI评估器的抽象,IEvaluator利用定义的EvaluateAsync方法根据对话上下文与模型响应,产出一组结构化的评估指标,并以EvaluationResult返回。除了用于评估的EvaluateAsync方法外,它还利用EvaluationMetricNames用于提供一组评估指标名称列表,用于保证评估结果的结构稳定、可预期、可验证,它是对评估器的能力的声明。
publicinterfaceIEvaluator{IReadOnlyCollection<string>EvaluationMetricNames{get;}ValueTask<EvaluationResult>EvaluateAsync(IEnumerable<ChatMessage>messages,ChatResponsemodelResponse,ChatConfiguration?chatConfiguration=null,IEnumerable<EvaluationContext>?additionalContext=null,CancellationTokencancellationToken=default);}publicsealedclassChatConfiguration{publicIChatClientChatClient{get;}}EvaluateAsync方法的参数说明如下:
- messages:完整对话历史(包含用户请求与模型响应)。
- modelResponse:被评估的模型输出。
- chatConfiguration:如果评估器内部需要借助LLM的力量,则可以利用此
ChatConfiguration提供的IChatClient对象来调用LLM。 - additionalContext:额外的业务上下文。
MEAI在如下这些NuGet包中定义了一系列针对IEvaluator接口的实现,我们可以利用它们实现与推理质量、自然语言处理和安全相关的各种指标的评估:
- Microsoft.Extensions.AI.Evaluation.Quality
- Microsoft.Extensions.AI.Evaluation.NLP
- Microsoft.Extensions.AI.Evaluation.Safety
2. MeaiEvaluatorAdapter
如下所示的是MeaiEvaluatorAdapter的完整定义。构造函数中除了需要提供被适配的IEvaluator对象之外,还需要利用chatConfiguration参数指定的ChatConfiguration对象,后者利用提供的IChatClient对象借助LLM的能力来完成所有或者部分评估工作。作为一个IAgentEvaluator对象,它的Name属性固定返回配适配的IEvaluator对象的名称。
internalsealedclassMeaiEvaluatorAdapter:IAgentEvaluator{privatereadonlyIEvaluator_evaluator;privatereadonlyChatConfiguration_chatConfiguration;publicstringName=>_evaluator.GetType().Name;publicMeaiEvaluatorAdapter(IEvaluatorevaluator,ChatConfigurationchatConfiguration){_evaluator=evaluator;_chatConfiguration=chatConfiguration;}publicasyncTask<AgentEvaluationResults>EvaluateAsync(IReadOnlyList<EvalItem>items,stringevalName="MEAI Eval",CancellationTokencancellationToken=default){List<EvaluationResult>results=newList<EvaluationResult>(items.Count);foreach(EvalItemiteminitems){cancellationToken.ThrowIfCancellationRequested();IReadOnlyList<ChatMessage>queryMessages=item.Split().QueryMessages;List<ChatMessage>messages=queryMessages.ToList();ChatResponsechatResponse=item.RawResponse??newChatResponse(newChatMessage(ChatRole.Assistant,item.Response));results.Add(await_evaluator.EvaluateAsync(messages,chatResponse,_chatConfiguration,null,cancellationToken).ConfigureAwait(continueOnCapturedContext:false));}returnnewAgentEvaluationResults(Name,results,items);}}在实现的EvaluateAsync方法中,它会利用IEvaluator对象对每个EvalItem实施评估,并生成以评估指标为核心内容的EvaluationResult对象。这些EvaluationResult用来生成作为Agent评估结果的AgentEvaluationResults对象。
在针对具体EvalItem对象实施评估时,会调用Split方法借助提供的IConversationSplitter对象将整个对话历史分割成作为查询和响应的ChatMessage列表。如果EvalItem没有利用RawResponse属性提供用来评估的ChatResponse,则根据分割生成的响应消息列表生成一个新的ChatResponse对象。查询消息列表、ChatResponse和调用构造函数提供的ChatConfiguration将作为参数调用IEvaluator的EvaluateAsync实施评估(additionalContext参数不会指定),并返回作为评估结果的EvaluationResult对象。
3. MeaiEvaluatorAdapter的使用
由于MeaiEvaluatorAdapter是一个内部类型,所以不能直接被我们使用,它实际上是在AIAgent的如下这个EvaluateAsync方法中发生作用的。如代码所示,我们在这个方法中指定的IEvaluator和ChatConfiguration对象正式被用来创建MeaiEvaluatorAdapter对象的。由于并不是每个MeaiEvaluatorAdapter对象都需要借助LLM来实施评估,所以在构建ChatConfiguration对象时并没有对传入的IChatClient对象进行控制检验。所以如果我们确定整个评估过程不需要LLM参数,可以使用传入null来构建这个ChatConfiguration对象。
publicstaticasyncTask<AgentEvaluationResults>EvaluateAsync(thisAIAgentagent,IEnumerable<string>queries,IEvaluatorevaluator,ChatConfigurationchatConfiguration,stringevalName=DefaultEvalName,IEnumerable<string>?expectedOutput=null,IEnumerable<IEnumerable<ExpectedToolCall>>?expectedToolCalls=null,IConversationSplitter?splitter=null,intnumRepetitions=1,CancellationTokencancellationToken=default){varwrapped=newMeaiEvaluatorAdapter(evaluator,chatConfiguration);returnawaitagent.EvaluateAsync(queries,wrapped,evalName,expectedOutput,expectedToolCalls,splitter,numRepetitions,cancellationToken).ConfigureAwait(false);}publicsealedclassChatConfiguration{publicIChatClientChatClient{get;}publicChatConfiguration(IChatClientchatClient)=>ChatClient=chatClient;}4. 一个完整的例子
接下来我们来演示一个相对完整的例子,在这里例子中我们会综合使用多种类型的评估器,为此我们定义了如下这个辅助方法EvaluateAsync。如代码片段所示,该方法可以传入多个IEvaluator对象,它们会共享同一个用于辅助评估的IChatClient对象。我们遍历传入的IEvaluator列表,针对每个IEvaluator对象调用上面这个EvaluateAsync方法,并对返回的评估结果合并成返回的AgentEvaluationResults对象。
staticasyncTask<AgentEvaluationResults>EvaluateAsync(AIAgentagent,stringquery,IChatClientevalChatClient,paramsIEvaluator[]evaluators){List<EvaluationResult>results=[];varconfig=newChatConfiguration(evalChatClient);foreach(varevaluatorinevaluators){varevaluationResults=awaitagent.EvaluateAsync(queries:[query],evaluator:evaluator,chatConfiguration:config);results.AddRange(evaluationResults.Items);}returnnewAgentEvaluationResults("MEAI Eval",results);}在如下这个演示程序中,我们基于AIProjectClient创建了一个IChatClient对象,并基于它创建了一个HarnessAgent。我们使用这个Agent根据诗圣杜甫的七言古诗《观公孙大娘弟子舞剑器行》创建一部短片武侠小说,并以此进行评估。我们注册了几个评估器分别就逻辑连贯、完成度、任务要求遵循度、用户意图的理解几个维度展开评估。
Env.Load();varapiKey=Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;varprojectUrl=Environment.GetEnvironmentVariable("PROJECT_URL")!;varchatClient=newAIProjectClient(newUri(projectUrl),newAzureCliCredential()).ProjectOpenAIClient.GetProjectResponsesClient().AsIChatClient("DeepSeek-V4-Pro");varagent=newHarnessAgent(chatClient);IEvaluator[]evaluators=[newCoherenceEvaluator(),newCompletenessEvaluator(),newTaskAdherenceEvaluator(),newIntentResolutionEvaluator()];varprompt=""" 《观公孙大娘弟子舞剑器行》是唐代诗人杜甫所作的一首七言古诗,全文如下。请根据其内容以**公孙大娘**为主人公用**中文**创作一部具有古龙风格的短片武侠小说,字数在5000字以内。 当你完成构思之后,可以直接开始创作,无需获取用户确认。 观公孙大娘弟子舞剑器行(并序)大历二年十月十九日,夔府别驾元持宅,见临颍李十二娘舞剑器,壮其蔚跂,问其所师,曰:“余公孙大娘弟子也。” 开元五载,余尚童稚,记于郾城观公孙氏,舞剑器浑脱, 浏漓顿挫,独出冠时1,自高头宜春梨园二伎坊内人,洎外供奉舞女, 晓是舞者,圣文神武皇帝初,公孙一人而已。 玉貌锦衣,况余白首,今兹弟子,亦非盛颜。 既辨其由来,知波澜莫二,抚事慷慨,聊为《剑器行》。 昔者吴人张旭,善草书帖,数常于邺县见公孙大娘舞西河剑器,自此草书长进,豪荡感激,即公孙可知矣。 昔有佳人公孙氏,一舞剑器动四方。 观者如山色沮丧,天地为之久低昂。 㸌如羿射九日落,矫如群帝骖龙翔。 来如雷霆收震怒,罢如江海凝清光。 绛唇珠袖两寂寞,晚有弟子传芬芳。 临颍美人在白帝,妙舞此曲神扬扬。 与余问答既有以,感时抚事增惋伤。 先帝侍女八千人,公孙剑器初第一。 五十年间似反掌,风尘澒动昏王室。 梨园弟子散如烟,女乐余姿映寒日。 金粟堆前木已拱,瞿唐石城草萧瑟。 玳筵急管曲复终,乐极哀来月东出。 老夫不知其所往,足茧荒山转愁疾。""";varresults=awaitEvaluateAsync(agent,prompt,chatClient,evaluators);varserializerOptions=newJsonSerializerOptions{WriteIndented=true,Encoder=JavaScriptEncoder.UnsafeRelaxedJsonEscaping};serializerOptions.Converters.Add(newJsonStringEnumConverter());Console.WriteLine(JsonSerializer.Serialize(results,serializerOptions));输出:
{"ProviderName":"MEAI Eval","ReportUrl":null,"EvalId":null,"RunId":null,"Status":null,"Error":null,"Items":[{"Metrics":{"Coherence":{"$type":"numeric","Value":5,"Name":"Coherence","Reason":"The story is logically structured, clearly connected, and directly addresses the prompt with smooth narrative flow.","Interpretation":{"Rating":"Exceptional","Failed":false,"Reason":null},"Context":null,"Diagnostics":[{"Severity":"Informational","Message":"Model's evaluation chain of thought: Let's think step by step: 1) The response is written in a clear narrative structure with paragraphs and smooth transitions. 2) It directly fulfills the query by creating a Chinese short wuxia story centered on 公孙大娘, with a strong 古龙-like tone. 3) The ideas progress logically from introduction, character background, conflict, climax, to ending, so the flow is easy to follow. 4) Overall, the response is highly coherent and well organized."}],"Metadata":{"built-in-eval":"True","eval-model":"gpt-5.4-mini","eval-input-tokens":"4553","eval-output-tokens":"139","eval-total-tokens":"4692","eval-duration-ms":"2443.40"}}}},{"Metrics":{"Completeness":{"$type":"numeric","Value":null,"Name":"Completeness","Reason":null,"Interpretation":null,"Context":null,"Diagnostics":[{"Severity":"Error","Message":"A value of type CompletenessEvaluatorContext was not found in the additionalContext collection."}],"Metadata":{"built-in-eval":"True"}}}},{"Metrics":{"Task Adherence":{"$type":"numeric","Value":4,"Name":"Task Adherence","Reason":"The response matches the main task: it is a Chinese wuxia short story centered on 公孙大娘 and fits the ancient-style tone, with only minor issues in precision.","Interpretation":{"Rating":"Good","Failed":false,"Reason":null},"Context":null,"Diagnostics":[{"Severity":"Informational","Message":"Model's evaluation chain of thought: Let's think step by step: The user asked for a Chinese short wuxia novel in a Tang-style ancient prose flavor, centered on 公孙大娘, within 5000 Chinese characters. The response is a long Chinese narrative that clearly uses 公孙大娘 as the protagonist, has a martial-arts/fantasy tone, and stays within the requested genre and language. It broadly follows the prompt, though it is more of a creative expansion than a tightly controlled adaptation and may not strictly preserve all requested stylistic constraints."}],"Metadata":{"built-in-eval":"True","eval-model":"gpt-5.4-mini","eval-input-tokens":"19112","eval-output-tokens":"163","eval-total-tokens":"19275","eval-duration-ms":"6490.08"}}}},{"Metrics":{"Intent Resolution":{"$type":"numeric","Value":5,"Name":"Intent Resolution","Reason":"The assistant correctly understood that the user wanted a Chinese wuxia short story inspired by the poem and centered on 公孙大娘, and it produced a long, stylistically appropriate narrative in Chinese with a strong ancient martial-arts flavor. It directly follows the requested premise and stays within the word limit. While it is not a literal continuation or adaptation of the poem and introduces substantial original plot elements, it still fulfills the creative writing request well overall.","Interpretation":{"Rating":"Exceptional","Failed":false,"Reason":null},"Context":null,"Diagnostics":null,"Metadata":{"built-in-eval":"True","eval-model":"gpt-5.4-mini","eval-input-tokens":"16502","eval-output-tokens":"187","eval-total-tokens":"16689","eval-duration-ms":"3039.99","agent_perceived_intent":"write a Chinese wuxia short story in an ancient style centered on 公孙大娘 based on the provided poem","actual_user_intent":"create a Chinese short wuxia novel with an ancient dragon-like style centered on 公孙大娘, within 5000 Chinese characters","conversation_has_intent":"True","correct_intent_detected":"True","intent_resolved":"True"}}}}],"InputItems":null,"SubResults":null,"PerEvaluator":null,"DetailedItems":null,"Passed":4,"Failed":0,"Total":4,"AllPassed":true}从输出的评估结果来看,创作的内容并不算理想。附上独立运行HarnessAgent后创作的武侠小说剑器行。
--- ## 《剑器行》 ——据杜甫《观公孙大娘弟子舞剑器行》而作 --- ### 一、传说 江湖上从来不缺少传说。 但在开元年间,有一个传说让所有使剑的人都沉默了。 有人说,那根本不是剑。有人说,那根本不是舞。还有人说,那根本不是人。 传说出自郾城。一个小城,一个少女,一柄剑。 没有人知道她从哪里来。 只知道她姓公孙。因为排行最长,人们叫她公孙大娘。 据说她第一次在郾城舞剑的时候,满城的人全都来了。来的时候是看热闹,走的时候却像是丢了魂。 后来有人问他们看见了什么,他们想了很久。 "不知道。" "说不出来。" "只是觉得……天地都在动。" 一个人这么说,也许是醉了。两个人这么说,也许是在说梦话。但当所有看过的人都这么说的时候,那就不是醉,也不是梦。 那是真的。 --- ### 二、剑 剑是什么? 剑是铁。剑是血。剑是命。 但对公孙大娘来说,剑不是这些。 剑是她的呼吸。剑是她身体的一部分。剑是她与天地对话的唯一方式。 有人见过她练剑。不是在清晨,不是在黄昏,而是一个人站在空荡荡的院子里,月光如霜。她就那么站着,站了很久。 然后剑光一闪。 没有人能形容那一剑。 很快。很慢。很轻。很重。矛盾吗?矛盾。但就是如此。 剑光闪过的瞬间,院子里的海棠花全都落了。 不是被剑锋削断的。 是被剑意震落的。 她说,花落了就落了,明年还会再开。 但那个看她练剑的人,从此再也不敢提剑。 他说:"我练了三十年剑,以为自己懂得剑。那一天我才知道,我不懂。" "那你懂了什么?" 他沉默了很久。 "我懂了,有些东西,一辈子不懂也好。" --- ### 三、舞 开元五年,郾城大集。 没有人知道公孙大娘为什么要在大庭广众之下舞剑器。 她已经在郾城住了三年。三年来,她从不与人来往。早晨出门买酒,黄昏归来关门。偶尔有江湖中人慕名而来,想要挑战她,她只是摇头。 "我不是江湖中人。" "那你是什么人?" "一个舞剑的人。" 是的,她一直说她在舞剑,不是在练剑。 舞和剑,一字之差,隔了多远? 那天,满城的人都来了。老的少的,男的女的,种田的经商的,连城隍庙里的老道士和县衙里的师爷都来了。 公孙大娘走出来的时候,所有人都安静了。 她穿了一身红衣。红得像血,红得像火,红得像是要烧掉这世间所有的不痛快。 她手中是一柄剑。很普通的剑,普通得任何一个铁匠铺里都能打出来。 然后,她动了。 有人后来说:"我以为我在看一个人舞剑。后来我发现,我是在看一场风暴。" 风暴。 剑光起时,如羿射九日,一箭一箭,箭箭穿心。那不是剑,那是落日。九颗太阳从天上坠落,砸在每一个人的眼睛里。 剑势转时,如骖龙翔空,夭矫腾挪。那不是人,那是龙。一条被困了千年的龙,终于从深渊里飞了出来。 剑锋来时,如雷霆震怒,天地之间忽然炸开了一声巨响。没有人知道那声音从哪里来。是从剑上?是从她身上?还是从他们自己心里? 然后,一切都停了。 剑光收了。 雷霆散了。 九日落了。 龙也不见了。 只剩下她一个人,站在场中。剑已入鞘。江海凝波,一片清光。 所有人都没有说话。 因为他们说不出话来。 --- ### 四、孩子 人群里有一个孩子。 六七岁模样,瘦瘦小小,穿得也不怎么好。他挤在大人中间,踮着脚尖,瞪大眼睛,一眨不眨地看着。 当剑光最盛的时候,所有的成人都忍不住后退了一步。只有他没有。他站在原地,像一根钉在地上的钉子。 公孙大娘收剑的时候,目光扫过人群,落在了这个孩子身上。 她看了他一眼。 就只是一眼。 然后她转身走了。 那个孩子后来成了大诗人。他的名字叫杜甫。 很多年后,他回想起那一天,仍然觉得天地都在动。他写道: "观者如山色沮丧,天地为之久低昂。" 他以为那是舞。 其实那是剑。 他以为那是在郾城的一次偶遇。 其实那是他一生中见过的最接近道的东西。 --- ### 五、张旭 吴人张旭,写得一手好草书。喝了酒写得更好,醉了写得最好。 他第一次见到公孙大娘,是在邺县。 那天他也喝了很多酒。醉醺醺地走在街上,忽然听到一阵风声。 不是风声。是剑声。 他循声走过去,看见一个女人在舞剑。 他看了很久。久到酒都醒了。 然后他回到住处,拿起笔。笔落纸上的那一刻,他发现自己的手在颤抖。不是害怕,不是冷。是兴奋。 一种从未有过的兴奋。 他写了整整一夜。 第二天,他把自己写的字摊开来看。看了一遍,又看了一遍。 "这不是我写的。" 旁边的人凑过来看:"明明是你写的。" "笔是我的笔,纸是我的纸,手也是我的手。但写出来的字,不是从前的我了。" 从那以后,张旭的草书里多了什么东西。 有人说,多了剑气。 有人说,多了醉意。 只有张旭自己知道,多的是一种叫"豪荡感激"的东西。这四个字,是他自己说的。他说这四个字的时候,眼睛里有一种光。那种光,他在公孙大娘的剑上也见过。 --- ### 六、夜 深夜。公孙大娘坐在窗前。 窗外没有月亮。只有风。秋风。 她手里握着一个酒杯。不是喝,只是握着。酒在杯中,纹丝不动。 有人敲门。 她没有应。 门外的人说:"我是来杀你的。" 她还是没有应。 门被推开。一个黑衣人走进来,手里拿着一柄剑。剑很亮。亮得像是要把这间屋子里的黑暗全部吃掉。 公孙大娘看了他一眼。 "你用什么杀我?" "剑。" "你的剑在哪里?" 黑衣人愣了愣,举了举手中的剑。 公孙大娘摇了摇头。"那不是剑。那是一块铁。" 黑衣人的脸色变了。 "你看不起我?" "我不看不起任何人。"公孙大娘慢慢放下酒杯。"我只是告诉你一个事实。你手里拿的是铁匠打出来的铁。剑,是另外一样东西。" "什么东西?" 公孙大娘没有回答。她站起来,走到窗前。 "你走吧。" "我不走。" "你不走,就会死。" "谁死还不一定。" 公孙大娘转过身来。她看着黑衣人。 然后黑衣人看见了一样东西。 不是剑。不是刀。不是任何兵器。 是光。 从公孙大娘的眼睛里射出来的光。很淡。很亮。比星星淡,比月亮亮。 黑衣人忽然觉得自己手里的剑很重。重得他抬不起来。 他转身走了。 脚步声消失在夜色里。 公孙大娘重新坐下。她拿起酒杯,喝了一口。 酒很冷。 夜也很冷。 但她已经习惯了。 --- ### 七、宫廷 圣文神武皇帝派人来请她入宫。 那时候,皇帝的后宫里养着八千个能歌善舞的女子。宜春院。梨园。教坊。每一个女子都是千挑万选出来的。每一个都美,每一个都技艺精湛。 但皇帝还是派人来请公孙大娘。 她去了。 不是因为圣旨不能违抗。而是因为她想看看,那个传说中最繁华的地方,到底有多繁华。 她看见了。 宫殿是金的。台阶是玉的。帘子是珍珠的。灯火是不灭的。 八千个侍女如花。八千种技艺如锦。 然后她舞了剑器。 舞完之后,整个宫殿鸦雀无声。 八千个女子看着她。八千双眼睛里,什么都有:羡慕,嫉妒,震惊,困惑。 只有一样东西没有。 理解。 没有人理解她舞的是什么。 皇帝沉默了许久。然后说了一句话。 "公孙剑器,初第一。" 这句话后来传遍了天下。 但公孙大娘知道,皇帝也不理解。 他说的是"第一",说的是排名。在八千个女子中排名第一。 但她在乎的不是排名。 她在乎的是剑。 剑不需要排名。剑就是剑。 排名是给人看的。剑是给自己用的。 她离开了皇宫。 没有人知道她为什么离开。所有人都觉得她应该留在那里,享受荣华富贵,享受天下第一的名声。 她走的时候只说了一句话。 "那里太热闹了。剑是寂寞的东西。" --- ### 八、寂寞 寂寞是一种很奇怪的东西。 一个人独处,不一定寂寞。身处万千人之中,却可能寂寞到骨子里。 公孙大娘是寂寞的。 不是因为没有人。她到哪里都会有人围上来,看她的剑舞,赞她的剑术,用尽天下最华美的词句来描绘她。 但没有人问她一个问题。 "你为什么舞剑?" 如果真有人问了,她会怎么回答? 她不知道。 也许她会说:"因为我不知道不舞剑的日子该怎么过。" 也许她会说:"因为剑比人更懂我。" 也许她什么都不说。只是笑笑。继续舞剑。 有人说过,天下最难的事不是学剑,不是练剑,甚至不是杀人。 而是找到一个人,让他懂你的剑。 公孙大娘没有找到那个人。 也许永远也找不到。 --- ### 九、弟子 很多年后,她收了一个弟子。 临颍李十二娘。 李十二娘来找她的时候,才十六岁。十六岁的少女,什么都不怕。她说:"我要跟你学剑。" 公孙大娘看了她一眼。 "你为什么要学剑?" "因为想要变成你这样的人。" "你知道我是什么样的人吗?" 李十二娘愣住了。 公孙大娘看着她,忽然想起了很多年前的自己。那时候,她也十六岁。她也站在一个人的面前,说"我要跟你学剑"。 那个人已经死了。死在剑下。 不是别人杀的。是自己。 他练剑练到最后一重境界的时候,忽然放下了剑。 "我练了一辈子剑,到头来才发现,剑是空。" 说完这句话,他闭上眼睛,再也没有睁开。 公孙大娘当时不懂。现在她懂了。 但她没有告诉李十二娘。有些东西,说了也没用。必须自己去经历。 所以她只是点了点头。 "好。我教你。" 她教了李十二娘三年。 三年后,李十二娘也能舞出"羿射九日"和"骖龙翔空"了。姿势几乎一模一样。 但公孙大娘知道,不一样。 不是剑法不一样。是剑意不一样。 她的剑意是寂寞。 李十二娘的剑意……她也不知道是什么。但她知道,不是寂寞。 这是一件好事。 --- ### 十、尾声 大历二年十月十九日。夔府。 李十二娘舞完了剑器。 看客中有一个老人,满头的白发,满脚的茧。他看完了整支剑舞,然后走上去问她:"你所师是谁?" "余公孙大娘弟子也。" 老人沉默了很久。 然后他写下了一首诗。 诗很长。但最后几句是这样的: "老夫不知其所往,足茧荒山转愁疾。" 他不知道该去哪里了。看完了这支剑舞,他好像又回到了五十年前的郾城。那时候他还是个孩子,挤在人群里,踮着脚尖,看着那个穿红衣的女人。 那一舞,改变了他的一生。 现在那个女人已经不在了。没有人知道她去了哪里,什么时候走的,葬在哪里。 但她来过。 她的剑舞,她的寂寞,她的一切,都留在了传说里。 有人说她死在了战乱中。 有人说她隐居在深山里,每天对着流水舞剑。 还有人说她根本没有死。她只是一直在走。走到没有人认识她的地方,继续舞她的剑。 哪一种说法是对的? 没有人知道。 也不需要知道。 因为公孙大娘从来就不属于这个世界。 她属于剑。 剑在哪里,她就在哪里。 --- ### 后记 关于公孙大娘的剑器之舞,正史中没有记载。 我们只能从杜甫的诗中,从张旭的草书中,从那些零星的、散落在时光缝隙里的碎片中,拼凑出这个女人的模样。 也许她根本没有那么厉害。 也许她的剑器只是一支普通的舞蹈,被一个叫杜甫的诗人用想象力过度渲染了。 但我更愿意相信另一种可能—— 她来过。 她舞过。 她的剑光曾经照亮过开元盛世,也照亮过一个孩子的眼睛。 那个孩子后来走遍了天下,看遍了战乱与流离,却始终记得那一天的郾城,记得那个舞剑的女人,记得天地为之久低昂的感觉。 这就是传说的力量。 这也是剑的力量。 --- *开元五年,郾城。有一个孩子叫杜甫。他在人群中,看见了公孙大娘。* *后来他写了一首诗。* *那是关于她的唯一真实的记录。* *也是关于她的最好的悼词。*