
1. 项目缘起当大语言模型“看”不懂一张图最近在折腾几个开源大语言模型想让它帮我分析一些简单的图表数据。我随手丢给它一个用字符画的柱状图类似下面这样产品A: ████████████████████ (200) 产品B: ████████████ (120) 产品C: ████████████████████████ (250)我的问题是“哪个产品的销量最高具体数值是多少” 按理说这问题对小学生都毫无难度。但模型的回答却让我哭笑不得它要么说“根据文本描述产品C的柱状最长可能销量最高”要么干脆把“████”当成一段无意义的乱码字符给忽略掉直接分析起后面的数字得出完全错误的结论。这让我意识到一个关键问题我们常说的大语言模型LLM的“多模态”或“视觉”能力往往依赖于专门的视觉编码器如CLIP来处理真正的像素图像。但对于大量存在于纯文本环境中的ASCII艺术图、字符表格、简单布局模型其实是个“睁眼瞎”。它缺乏一种基础的空间推理能力——即理解字符在二维平面上的相对位置、排列组合所构成的空间关系和视觉含义的能力。这种能力重要吗非常重要。它不仅是让模型理解技术文档中的流程图、系统架构图常以字符画形式出现的基础也是提升其代码理解代码缩进即是一种空间布局、文档解析识别文本对齐的表格、乃至进行简单几何推理的关键。一个无法理解“█”字符堆叠起来代表高度的模型在现实世界的许多文本交互场景中其能力是有严重缺陷的。于是一个想法自然浮现能否通过一种轻量、低成本的方式专门训练大语言模型这种基于纯文本的空间推理能力这就是“通过ASCII布局构造训练”项目的核心动机。我们不引入复杂的图像模块就利用模型最熟悉的文本Token教会它“看见”并理解字符背后的二维世界。2. 核心原理将空间关系转化为语言模型的“阅读”任务要让一个基于序列Transformer的大语言模型理解二维空间我们需要进行一次思维转换将空间布局问题重新定义为一个特殊的文本理解和生成问题。大语言模型的基本功是预测下一个Token。它擅长处理序列依赖即一个词之后可能跟着什么词。而二维空间关系本质上是上下左右、包含、相邻等关系的集合。我们的训练目标就是让模型在“阅读”一行行ASCII文本时不仅能理解字符本身的语义还能在内部构建出这些字符的“心理坐标”并学会用自然语言描述或基于此坐标进行推理。2.1 ASCII布局的“坐标化”与特征抽取首先我们需要将ASCII艺术图这种“文本形式的图像”进行结构化解析。假设我们有一幅简单的ASCII画比如一个盒子---- | | | | ----对于模型来说输入就是这五行字符串。但直接输入模型只会将其视为5个独立的文本行。因此在构造训练数据时我们需要注入空间信息。一种有效的方法是隐式坐标编码绝对位置提示在每行文本前添加一个不起眼的位置标记。例如用[Line:0]、[Line:1]...来暗示行号。这可以通过在训练样本的system prompt或少量示例中引入这种格式来实现让模型潜移默化地建立“行号”与“垂直位置”的关联。相对位置注意力Transformer本身具有位置编码但那是针对一维序列的。我们可以通过设计训练任务让模型必须利用字符在序列中的相对远近来推断二维空间中的相邻关系。例如判断两个“”是否属于同一个矩形就需要模型跨越中间的“-”和“|”字符建立联系。结构描述配对这是训练的关键。我们生成海量的ASCII布局图并同时生成对应的自然语言空间描述。例如针对上面的盒子描述可以是“这是一个由字符‘’和‘-’构成的上边框位于第0行。第1到第3行是左右由‘|’字符构成的竖边中间是空格。下边框与上边框对称位于第4行。” 更复杂的描述可以是“盒子左上角顶点在(0,0)右上角在(0,4)高度为3个字符单位。”通过让模型学习从ASCII布局到结构描述的映射我们实际上是在训练它内部生成一种空间特征的中间表示。2.2 训练任务设计从识别、描述到推理单纯的“看图说话”不够我们需要设计一系列由易到难的任务来渐进式地提升模型的空间推理能力元素识别与定位给定一个ASCII图询问特定字符的位置或统计特定字符的数量。示例输入[ASCII图] 问题字符‘’出现了几次分别在第几行目标训练模型进行视觉搜索和计数。空间关系描述要求模型用自然语言描述布局中元素之间的关系。示例输入[ASCII图] 问题描述字符‘A’和字符‘B’的相对位置。期望输出“A位于B的正上方中间间隔一行。”布局重构给出一个空间描述让模型生成或补全ASCII图。这是生成任务能极大强化模型对描述与布局对应关系的理解。示例输入“画一个宽为5个字符高为3个字符的矩形用‘#’做边框。”期望输出##### # # #####基于空间的逻辑推理这是高级任务融合了空间理解和逻辑判断。示例输入[一个用字符表示的房间、门、钥匙的ASCII地图] 问题从起点‘S’出发能拿到钥匙‘K’并走到门‘D’吗为什么期望输出“可以。路径是S向右移动两格向下移动一格拿到K然后向上移动一格再向右移动三格即可到达D。中间没有障碍物‘█’阻挡。”通过混合这些任务进行多任务训练模型被迫在它的参数空间中为ASCII字符序列开辟出处理二维几何关系的“功能区”。3. 实战构造训练数据与微调策略理论说完了我们来点实际的。想要训练模型高质量、大规模的训练数据是核心。完全手工制作是不现实的我们必须采用程序化生成的方法。3.1 自动化生成ASCII布局与描述对我们可以编写一个数据生成引擎其核心流程如下import random import numpy as np def generate_ascii_box(): 生成随机大小的矩形框及其描述 width random.randint(3, 10) height random.randint(2, 6) # 生成ASCII矩形 top_bottom - * (width - 2) if width 2 else middle | * (width - 2) | if width 2 else || ascii_art [top_bottom] [middle for _ in range(height-2)] [top_bottom] ascii_str \n.join(ascii_art) # 生成结构化描述 description f这是一个矩形ASCII图形。外框由字符和-构成内部填充空格。 description f图形宽度为{width}个字符包含边框高度为{height}行。 description f左上角坐标为(0,0)右上角坐标为(0,{width-1})。 description f边框的竖线字符|位于第1列和第{width-1}列0起始索引。 # 生成各种QA对 qa_pairs [] # 任务1元素识别 qa_pairs.append({ question: 这个图形中字符出现了几次, answer: str(2 * (2 if height 1 else 1)) # 计算角点数量 }) # 任务2空间关系 qa_pairs.append({ question: 顶部边框和底部边框在形状上是什么关系, answer: 它们是相同的都是由一个、若干个-和另一个组成的水平线段。 }) # 任务3推理 if width 4 and height 3: qa_pairs.append({ question: f如果点(1,1)代表内部空间的一个点它到左边框的横向距离是多少个字符, answer: 1个字符。因为左边框是第0列的|点(1,1)在第1列。 }) return ascii_str, description, qa_pairs这个生成器可以无限扩展用于生成更复杂的图形多个图形的组合相交、相离、简单图表柱状图、折线图、流程图节点等。关键在于每一个生成的ASCII图都必须附带精确的、结构化的自然语言描述和多种形式的问答对。3.2 模型微调的技术选型与实操有了数据接下来就是选择模型和微调方法。对于这个任务我有以下几点建议基座模型选择优先选择代码能力强的开源模型如CodeLlama系列、DeepSeek-Coder、Qwen2.5-Coder。原因在于代码本身对缩进垂直空间和结构括号匹配可类比空间包含极度敏感这些模型已经具备了一定的隐式空间逻辑处理能力在此基础之上进行微调事半功倍。相比之下纯文本模型如Llama、Mistral的起点会更低。微调方法全参数微调Full Fine-tuning效果最好但成本最高。QLoRA是目前性价比最高的选择。它通过低秩适配器在少量GPU资源下实现接近全参数微调的效果非常适合我们这种定义明确的专项能力提升任务。训练格式采用对话格式进行训练。将ASCII图、问题、答案包装成多轮对话。例如使用ChatML格式|im_start|system 你是一个擅长分析ASCII图形和空间布局的助手。请根据给定的ASCII图回答问题。|im_end| |im_start|user [ASCII图] 问题字符‘*’位于第几行第几列|im_end| |im_start|assistant 字符‘*’位于第2行从0开始计数的第5列。|im_end|这种格式让模型更清晰地理解任务边界。一个具体的QLoRA训练命令示例使用Hugging Face PEFT和Transformers库# 假设我们已经将数据整理成了jsonl格式每条记录包含ascii, conversations字段 accelerate launch --num_processes4 \ run_sft.py \ --model_name_or_path codellama/CodeLlama-7b-Instruct-hf \ --dataset_path ./ascii_spatial_data.jsonl \ --output_dir ./output_ascii_spatial \ --num_train_epochs 3 \ --per_device_train_batch_size 4 \ --gradient_accumulation_steps 8 \ --learning_rate 2e-4 \ --lr_scheduler_type cosine \ --warmup_ratio 0.03 \ --logging_steps 10 \ --save_strategy epoch \ --bf16 True \ --tf32 True \ --use_peft True \ --lora_r 64 \ --lora_alpha 16 \ --lora_dropout 0.1 \ --lora_target_modules q_proj,k_proj,v_proj,o_proj \ --dataset_text_field conversations \ --max_seq_length 2048 \ --packing False注意这里的关键参数是lora_target_modules针对LLaMA架构的模型通常定位到注意力层的投影模块。max_seq_length需要足够长以容纳多行的ASCII图和长描述。3.3 训练过程中的关键陷阱与调优在实际操作中你会遇到几个典型的坑模型“作弊”——绕过空间推理这是初期最容易出现的问题。例如你问“第3行的第5个字符是什么”模型可能学会直接从输入的文本序列中数到第3行以换行符为界然后数第5个Token而根本没有建立二维坐标概念。这只是在做序列索引不是空间推理。解决方案在数据中增加干扰项。例如在问题中采用不同的坐标表述“从左往右数第5列”、“从0开始的索引(2,4)”或者在ASCII图中插入不规则的缩进、在图形旁添加无关的解释文本迫使模型必须真正理解“视觉焦点”区域而不是简单地线性扫描。描述与布局的“对齐幻觉”模型可能会生成语法正确但空间描述错误的答案。例如它描述一个矩形“宽10高5”但实际生成的图宽是8。这是因为在训练初期语言建模的损失函数只关心描述文本本身的流畅度未能与空间结构强关联。解决方案在损失函数上做文章。除了标准的语言模型损失可以尝试添加一个辅助重建损失。即让模型在生成描述的同时也尝试根据描述或内部表示重新生成ASCII图然后计算与原图的编辑距离如Levenshtein距离将这个距离作为一个惩罚项加入总损失。这能强行建立描述与布局的对应关系。复杂图形下的性能崩溃模型处理5x5的盒子很好但遇到20x20带有多个内部结构的复杂图形时回答质量骤降。解决方案实施课程学习。在训练初期只使用简单、规则的图形矩形、三角形、水平/垂直线。随着训练进行逐步引入更复杂、不规则、多元素的图形。让模型先掌握基础的空间范式如边框、对齐、连接再学习组合逻辑。4. 效果评估与能力边界探测训练完成后如何判断模型真的“学会”了而不是“背会”了训练集我们需要一套系统的评估方法超越简单的准确率。4.1 设计多维度的评估基准我建议从以下几个维度构建测试集泛化能力未见过的图形元素训练集只用 - |画框测试时用# *等画框。尺度和比例变化训练集图形较小测试超大或超小图形。旋转与变形测试轻微旋转的字符线虽然ASCII艺术很难旋转但可以测试非对齐的图形。推理深度直接查询“A的左边是什么”简单。间接推理“如果将所有‘X’向右移动一格它会碰到什么”需要心理模拟。全局分析“这个布局中是否存在一条从左上角到右下角、不经过‘墙’字符的路径”类似寻路问题。组合能力将空间推理与模型的其他知识结合。例如给一个ASCII画的简单电路图用-表示导线表示连接点V表示电池问“电流的流向是怎样的”。4.2 案例分析训练前后的对比为了直观感受我对一个7B参数的代码模型进行了约10万对数据的QLoRA微调。以下是训练前后在相同测试问题上的表现对比测试用例1简单定位ASCII图:....O.... ...OOO... ..OOOOO.. .OOOOOOO. OOOOOOOOO问题: “最顶层的‘O’在第几行它下面一行有多少个‘O’”训练前模型“最顶层是‘....O....’所以‘O’在第0行。下面一行是‘...OOO...’有3个‘O’。”正确但可能是蒙的因为问题简单训练后模型“最顶层的‘O’位于第0行第4列从0开始计数。其正下方是第1行该行从第3列到第5列是‘O’共3个连续的‘O’字符。”回答更精确使用了坐标描述并指出了连续性测试用例2空间关系推理ASCII图(一个简单房间):------ |S K| | | | D ------ (S起点K钥匙障碍D门)问题“从S出发能拿到K然后到达D吗简述路径。”训练前模型“可以。先向右走拿到K然后向下再向右走到D。”完全忽略了障碍物‘’训练后模型“不能直接拿到K然后到达D。从S(0,1)到K(0,6)是畅通的。但从K(0,6)到D(3,7)需要经过(2,5)附近而(2,5)位置有一个障碍物‘’挡住了去路。需要寻找其他路径但此图中没有。”准确识别了障碍物及其位置并进行了正确的空间阻断分析可以看到训练后的模型不仅给出了答案还展示了其内部的空间坐标计算过程并且对障碍物这种关键空间元素有了敏感度。4.3 能力的边界与局限性必须清醒认识到这种方法的局限性分辨率极低ASCII艺术的“像素”是字符分辨率远低于真实图像。它只能表达非常抽象的空间概念无法处理精细形状、曲线、颜色、纹理。依赖规范输入模型对不规则、杂乱、含有大量噪声的ASCII艺术图处理能力会下降。它本质上学习的是一种“规范化的”空间语言。并非真正的视觉理解这只是符号化的空间推理。模型理解的是“-在右边”这种符号关系而不是真正的视觉特征。它无法将这种方法直接泛化到真实图像识别。上下文长度限制复杂的ASCII图可能很长会占用大量Token容易触及模型的上下文窗口限制。尽管如此这项训练的价值是明确的。它以一种极低的成本为纯文本大语言模型补上了一个重要的能力短板。经过训练的模型在处理技术文档、日志图表、代码结构图、以及任何需要从文本排列中提取空间信息的任务时将表现出显著的优势。它让模型离“真正理解它所读到的文本”更近了一步——毕竟人类的阅读从来都不只是理解单词序列也包括理解它们在页面上的布局所传递的信息。