Azure Search自定义OCR技能merged_content文本合并顺序异常问题
偏移插入失效核心是两个配置/逻辑错误:
- 技能执行顺序配置错误
- 自定义WebApi技能输出逻辑不符合自定义技能的1:1映射规则,导致MergeSkill无法匹配图片文本和对应偏移量,最终把所有OCR文本统一追加到原生文本末尾。
1. 技能执行顺序错误
Azure Cognitive Search的技能严格按照skills数组的从上到下顺序执行,你当前配置把MergeSkill放在自定义OCR技能前面:执行MergeSkill时,自定义OCR技能还未运行,/document/normalized_images/*/text路径下没有任何值,等后续OCR技能跑完生成text字段,MergeSkill早已执行完成,自然不会触发按偏移插入的逻辑。
官方示例中内置OCR技能始终放在MergeSkill之前,你参考配置时遗漏了顺序调整。
2. 自定义技能输出绑定错误
你的自定义技能context设置为/document/normalized_images/*,意味着Search会把文档拆分出的每一张内嵌图片作为独立请求记录发送给WebApi,每条请求的RecordId和单个图片节点一一绑定。而contentOffset根本不是内置OCR输出的特殊字段,是Search在PDF解析、拆分内嵌图片阶段,自动给每个normalized_images节点生成的原生属性,标记当前图片在原文档文本流中的位置。
你当前的C#代码逻辑存在明显问题:拿到单张图片的请求后,循环Read API返回的所有页识别结果,给同一个RecordId追加了多条输出值,直接破坏了自定义技能单条输入对应单条输出的规则,最终导致扩充树中/document/normalized_images/*/text集合的顺序,和同路径下contentOffset集合的顺序完全错位,MergeSkill匹配不到正确的(文本、偏移量)对,就会触发兜底逻辑,把所有待插入文本统一追加到原生文本末尾。
第一步:调整技能集执行顺序
把自定义WebApi OCR技能挪到MergeSkill之前,保证先生成图片OCR文本,再执行合并逻辑,调整后的技能数组参考:
"skills": [ { "@odata.type": "#Microsoft.Skills.Custom.WebApiSkill", "name": "#2", "context": "/document/normalized_images/*", "inputs": [ { "name": "image", "source": "/document/normalized_images/*" } ], "outputs": [ { "name": "text", "targetName": "text" } ] }, { "@odata.type": "#Microsoft.Skills.Text.MergeSkill", "name": "#1", "context": "/document", "insertPreTag": " ", "insertPostTag": " ", "inputs": [ { "name": "text", "source": "/document/content" }, { "name": "itemsToInsert", "source": "/document/normalized_images/*/text" }, { "name": "offsets", "source": "/document/normalized_images/*/contentOffset" } ], "outputs": [ { "name": "mergedText", "targetName": "merged_content" } ] } ]
第二步:修正自定义WebApi的返回逻辑
不需要循环Read API返回的所有页结果,单条请求只对应单张图片,你只需要返回当前请求对应单张图片的OCR结果,和传入的RecordId一一对应即可,禁止给同一个RecordId返回多条输出值。修正后的返回逻辑参考:
// 单条请求对应单张图片,仅处理当前传入的单张图 var ocrResult = await CallReadApiForSingleImage(value.Data.image); // 替换为你的单图Read API调用逻辑 var responseValue = new { RecordId = value.RecordId, Data = new { text = string.Join(" ", ocrResult.Lines?.Select(x => x.Text)) } }; output.Values.Add(responseValue); return new OkObjectResult(output);
结果验证
修改完成后可通过搜索服务的技能调试工具查看文档扩充树,确认两个状态:
- 每个
/document/normalized_images/*节点下有且仅有一个text字段,值为当前图片的OCR结果 - 每个节点下的
contentOffset数值和图片在文档中的位置顺序匹配(文档中越靠前的图片,offset值越小)
满足以上两个条件,MergeSkill就会自动按照偏移量把OCR文本插入到原生文本的对应位置,不会出现所有图片文本堆在末尾的问题。
内容的提问来源于stack exchange,提问作者michasaucer

